Cloud Studio✖️SpringBoot+Vue学生管理系统

前言

在这个博客中,我将介绍如何使用Cloud Studio打造一个基于Spring Boot和Vue的学生管理系统。该系统旨在提供一个简单而功能丰富的平台,用于管理学生的信息和课程,并提供一系列功能来增强教育管理的效率和便捷性。

学生管理系统主要包括以下功能:

学生信息管理:管理员可以添加、编辑和删除学生的基本信息,如姓名、年龄、性别、联系方式等。学生也可以登录系统查看并编辑自己的信息。

该学生管理系统提供了一个友好的用户界面,使用Vue作为前端框架,实现了响应式的设计和良好的用户体验。后端使用Spring Boot作为框架,提供数据的存储和处理,并通过API为前端提供数据。数据库使用MySQL进行存储。

通过集成Spring Boot和Vue,该学生管理系统实现了前后端的分离,提供了一个高效和可扩展的解决方案,使教务人员和学生能够更好地管理和交流学习相关的信息。

1.搭建环境

1.1 创建项目

  • 创建项目:exam-student-vue

1.2 添加坐标

image-20230721115147369

<!-- 父工程 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <!-- jar包版本 -->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.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>
    </properties>

    <!-- 导入需要依赖(坐标/jar包)   -->
    <dependencies>

        <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>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</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>
        <!--swagger2-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.7.0</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.7.0</version>
        </dependency>

    </dependencies>

1.3 拷贝properties文件

image-20230721115412175

#端口号
server.port=8080

#数据库基本配置
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/db3?useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=1234

#druid 连接池配置
#驱动
#spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#初始化连接池大小
spring.datasource.druid.initial-size=1
#最小连接数
spring.datasource.druid.min-idle=1
#最大连接数
spring.datasource.druid.max-active=20
#获取连接时候验证,会影响性能
spring.datasource.druid.test-on-borrow=true

# mybatis
# mybatis.type-aliases-package=com.czxy.domain.base
# mybatis.mapper-locations=classpath:mappers/*.xml
#mapper
mapper.not-empty=false
mapper.identity=MYSQL
#开启驼峰映射
mybatis.configuration.map-underscore-to-camel-case=true
mybatis.mapper-locations=classpath*:mapper/*.xml
#开启log4j打印SQL语句
logging.level.com.czxy.dao=debug

1.4 编写启动类

image-20230721115439383

package com.czxy;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author manor
 *  
 */
@SpringBootApplication
public class StudentVueApplication {
    public static void main(String[] args) {
        SpringApplication.run(StudentVueApplication.class, args);
    }
}

1.5 拷贝封装类

image-20230721160831515

1.6 拷贝配置类

2. 基本结构

2.1 初始化数据库

2.1.1 创建 数据库

create database db1010;
use db1010;

image-20201011220751401

2.1.2 建表语句

  -- 班级表
  create table tb_class(
    `c_id` varchar(32) primary key comment '班级ID',
    `c_name` varchar(50) comment '班级名称',
    `desc` varchar(200) comment '班级描述'
  );
  insert into tb_class(`c_id`,`c_name`,`desc`) values('c001','Java12班','。。。。');
  insert into tb_class(`c_id`,`c_name`,`desc`) values('c002','Java34班','。。。。');

  # 学生表
  create table tb_student(
    s_id varchar(32) primary key comment '学生ID',
    sname varchar(50) comment '姓名',
    age int comment '年龄',
    birthday datetime comment '生日',
    gender char(1) comment '性别',
    c_id varchar(32)
  );
  alter table tb_student add constraint foreign key (c_id) references tb_class (c_id);

  insert into tb_student(`s_id`,`sname`,`age`,`birthday`,`gender`,`c_id`) values('s001','赵三',19,'2001-01-17','1','c001');
  insert into tb_student(`s_id`,`sname`,`age`,`birthday`,`gender`,`c_id`) values('s002','钱四',19,'2001-05-16','1','c001');
  insert into tb_student(`s_id`,`sname`,`age`,`birthday`,`gender`,`c_id`) values('s003','孙五',18,'2002-03-15','1','c001');
  insert into tb_student(`s_id`,`sname`,`age`,`birthday`,`gender`,`c_id`) values('s004','李三',19,'2001-04-14','0','c002');
  insert into tb_student(`s_id`,`sname`,`age`,`birthday`,`gender`,`c_id`) values('s005','周四',19,'2001-02-13','0','c002');
  insert into tb_student(`s_id`,`sname`,`age`,`birthday`,`gender`,`c_id`) values('s006','王五',18,'2002-06-12','1','c002');

2.2 后端实现:domain、Mapper

image-20230721161022196

2.2.1 班级相关

  • JavaBean

    package com.czxy.domain;
    
    import javax.persistence.Column;
    import javax.persistence.Id;
    import javax.persistence.Table;
    
    /**
     * @author manor
     *  
     */
    @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;
    
        public String getCid() {
            return cid;
        }
    
        public void setCid(String cid) {
            this.cid = cid;
        }
    
        public String getCname() {
            return cname;
        }
    
        public void setCname(String cname) {
            this.cname = cname;
        }
    
        public String getDesc() {
            return desc;
        }
    
        public void setDesc(String desc) {
            this.desc = desc;
        }
    
        @Override
        public String toString() {
            return "Classes{" +
                    "cid='" + cid + '\'' +
                    ", cname='" + cname + '\'' +
                    ", desc='" + desc + '\'' +
                    '}';
        }
    }
    
    
    
  • Mapper

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

2.2.2 学生相关

  • JavaBean

    package com.czxy.domain;
    
    import com.fasterxml.jackson.annotation.JsonFormat;
    
    import javax.persistence.Column;
    import javax.persistence.Id;
    import javax.persistence.Table;
    import java.util.Date;
    
    /**
     * @author manor
     *  
     */
    @Table(name="tb_student")
    public class Student {
    
        @Id
        @Column(name="s_id")
        private String 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 String cid;         //班级外键
    
        private Classes classes;    //班级对象
    
        public String getSid() {
            return sid;
        }
    
        public void setSid(String sid) {
            this.sid = sid;
        }
    
        public String getSname() {
            return sname;
        }
    
        public void setSname(String sname) {
            this.sname = sname;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        public Date getBirthday() {
            return birthday;
        }
    
        public void setBirthday(Date birthday) {
            this.birthday = birthday;
        }
    
        public String getGender() {
            return gender;
        }
    
        public void setGender(String gender) {
            this.gender = gender;
        }
    
        public String getCid() {
            return cid;
        }
    
        public void setCid(String cid) {
            this.cid = cid;
        }
    
        public Classes getClasses() {
            return classes;
        }
    
        public void setClasses(Classes classes) {
            this.classes = classes;
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "sid='" + sid + '\'' +
                    ", sname='" + sname + '\'' +
                    ", age=" + age +
                    ", birthday=" + birthday +
                    ", gender='" + gender + '\'' +
                    ", cid='" + cid + '\'' +
                    ", classes=" + classes +
                    '}';
        }
    }
    
    
  • Mapper

    package com.czxy.mapper;
    
    import com.czxy.domain.Student;
    import tk.mybatis.mapper.common.Mapper;
    
    /**
     * @author manor
     *  
     */
    @org.apache.ibatis.annotations.Mapper
    public interface StudentMapper extends Mapper<Student> {
    
    }
    
    

3.后端实现

3.1 班级后端

image-20230721161113168

3.1.1 查询所有班级

  • service

    package com.czxy.service;
    
    import com.czxy.domain.Classes;
    import com.czxy.domain.Student;
    import com.czxy.mapper.ClassesMapper;
    import com.czxy.mapper.StudentMapper;
    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;
    
    /**
     * @author manor
     *  
     */
    @Service
    @Transactional
    public class ClassesService {
    
        @Resource
        private ClassesMapper classesMapper;
        @Resource
        private StudentMapper studentMapper;
    
        /**
         * 查询所有
         * @return
         */
        public List<Classes> findAll() {
            List<Classes> list = classesMapper.selectAll();
            return list;
        }
    }
    
  • controller

    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;
    
    /**
     * @author manor
     *  
     */
    @RestController
    @RequestMapping("/classes")
    public class ClassesController {
    
        @Resource
        private ClassesService classesService;
    
        /**
         * 查询所有
         * @return
         */
        @GetMapping
        public BaseResult findAll(){
            // 查询
            List<Classes> list = classesService.findAll();
            // 返回
            return BaseResult.ok("查询成功", list );
        }
    }
    

3.1.2 添加班级

  • service

        /**
         * 添加班级
         * @param classes
         * @return
         */
        public boolean save(Classes classes) {
            // 校验
            Classes find = classesMapper.selectByPrimaryKey(classes.getCid());
            if(find != null){
                throw new RuntimeException("ID已存在");
            }
            // 添加
            int count = classesMapper.insert(classes);
            return count == 1;
        }
    
  • controller

    /**
         * 添加班级
         * @param classes
         * @return
         */
        @PostMapping
        public BaseResult save(@RequestBody Classes classes){
            try {
                // 添加
                boolean result = classesService.save(classes);
                // 返回
                if(result){
                    return BaseResult.ok("添加成功");
                } else {
                    return BaseResult.error("添加失败");
                }
            } catch (Exception e) {
                return BaseResult.error(e.getMessage());
            }
        }
    

3.1.3 查询班级详情

  • service

        /**
         * 查询详情
         * @param classId
         * @return
         */
        public Classes findById(String classId){
            Classes classes = classesMapper.selectByPrimaryKey(classId);
            return classes;
        }
    
  • controller

    	/**
         * 查询详情
         * @param classId
         * @return
         */
        @GetMapping("/{id}")
        public BaseResult findById(@PathVariable("id") String classId ){
            // 查询
            Classes classes = classesService.findById(classId);
    
            if(classes != null) {
                // 返回
                return BaseResult.ok("查询成功", classes);
            } else {
                return BaseResult.error("查询失败");
            }
        }
    

3.1.4 更新班级

  • service

        /**
         * 更新操作
         * @param classes
         * @return
         */
        public boolean update(Classes classes){
            // 校验
            Classes find = classesMapper.selectByPrimaryKey(classes.getCid());
            if(find == null){
                throw new RuntimeException("ID不存在");
            }
            // 更新非空项
            int count = classesMapper.updateByPrimaryKeySelective(classes);
            return count == 1;
        }
    
  • controller

        /**
         * 更新操作
         * @param classes
         * @return
         */
        @PutMapping
        public BaseResult update(@RequestBody Classes classes){
            try {
                // 添加
                boolean result = classesService.update(classes);
                // 返回
                if(result){
                    return BaseResult.ok("更新成功");
                } else {
                    return BaseResult.error("更新失败");
                }
            } catch (Exception e) {
                return BaseResult.error(e.getMessage());
            }
        }
    

3.1.5 删除班级

  • service

        /**
         * 通过id删除详情
         * @param classId
         * @return
         */
        public boolean deleteById(String classId) {
            // 查询指定班级id的学生数
            Example example = new Example(Student.class);
            Example.Criteria criteria = example.createCriteria();
            criteria.andEqualTo("cid", classId);
            int studentCount = studentMapper.selectCountByExample(example);
            if(studentCount > 0) {
                throw new RuntimeException("班级已关联学生,不能删除");
            }
    
            int count = classesMapper.deleteByPrimaryKey(classId);
            return count == 1;
        }
    
  • controller

        /**
         * 查询详情
         * @param classId
         * @return
         */
        @DeleteMapping("/{id}")
        public BaseResult deleteById(@PathVariable("id") String classId ){
            try {
                // 查询
                boolean result = classesService.deleteById(classId);
                // 返回
                if(result){
                    return BaseResult.ok("删除成功");
                } else {
                    return BaseResult.error("删除失败");
                }
            } catch (Exception e) {
                return BaseResult.error(e.getMessage());
            }
        }
    

3.2 学生后端

image-20230721170212395

3.1.1 查询所有学生

  • StudentVo

    package com.czxy.vo;
    
    /**
     * @author manor
     *  
     */
    public class StudentVo {
        private String cid;     //班级
        private String sname;       //姓名
        private String startAge;    //开始年龄
        private String endAge;      //结束年龄
    
        public String getCid() {
            return cid;
        }
    
        public void setCid(String cid) {
            this.cid = cid;
        }
    
        public String getSname() {
            return sname;
        }
    
        public void setSname(String sname) {
            this.sname = sname;
        }
    
        public String getStartAge() {
            return startAge;
        }
    
        public void setStartAge(String startAge) {
            this.startAge = startAge;
        }
    
        public String getEndAge() {
            return endAge;
        }
    
        public void setEndAge(String endAge) {
            this.endAge = endAge;
        }
    
        @Override
        public String toString() {
            return "StudentVo{" +
                    "cid='" + cid + '\'' +
                    ", sname='" + sname + '\'' +
                    ", startAge='" + startAge + '\'' +
                    ", endAge='" + endAge + '\'' +
                    '}';
        }
    }
    
    
  • service

    package com.czxy.service;
    
    import com.czxy.domain.Classes;
    import com.czxy.domain.Student;
    import com.czxy.mapper.ClassesMapper;
    import com.czxy.mapper.StudentMapper;
    import com.czxy.vo.StudentVo;
    import com.github.pagehelper.PageHelper;
    import com.github.pagehelper.PageInfo;
    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;
    
    /**
     * @author manor
     *  
     */
    @Service
    @Transactional
    public class StudentService {
    
        @Resource
        private StudentMapper studentMapper;
    
        @Resource
        private ClassesMapper classesMapper;
    
    
        /**
         * 查询所有 + 分页
         * @return
         */
        public PageInfo<Student> findAllByCondition(StudentVo studentVo, Integer pageSize, Integer pageNum){
            // 拼凑条件
            Example example = new Example(Student.class);
            Example.Criteria criteria = example.createCriteria();
            if(studentVo != null){
                //等值查询
                if(studentVo.getCid() != null && !"".equals(studentVo.getCid())) {
                    criteria.andEqualTo("cid",studentVo.getCid());
                }
                // 模糊查询
                if(studentVo.getSname() != null && !"".equals(studentVo.getSname())) {
                    criteria.andLike("sname","%"+studentVo.getSname()+"%");
                }
                // 区间查询
                if(studentVo.getStartAge() != null && !"".equals(studentVo.getStartAge())){
                    criteria.andGreaterThanOrEqualTo("age",studentVo.getStartAge());
                }
                if(studentVo.getEndAge() != null && !"".equals(studentVo.getEndAge())) {
                    criteria.andLessThanOrEqualTo("age",studentVo.getEndAge());
                }
            }
    
            // 分页
            PageHelper.startPage(pageNum,pageSize);
    
            // 条件查询
            List<Student> list = studentMapper.selectByExample(example);
    
            // 关联查询
            for(Student student : list){
                // 查询班级外键对应的对象
                Classes classes = classesMapper.selectByPrimaryKey(student.getCid());
                student.setClasses(classes);
            }
    
            // 分页封装
            PageInfo pageInfo = new PageInfo(list);
            return pageInfo;
        }
    }
    
  • controller

    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;
    import java.util.List;
    
    /**
     * @author manor
     *  
     */
    @RestController
    @RequestMapping("/student")
    public class StudentController {
    
        @Resource
        private StudentService studentService;
    
        /**
         * 条件查询
         * @param studentVo
         * @return
         */
        @PostMapping("/condition/{pagesize}/{pagenum}")
        public BaseResult conditioin(@RequestBody StudentVo studentVo, @PathVariable("pagesize") Integer pagesize , @PathVariable("pagenum") Integer pagenum){
            // 添加
            PageInfo<Student> pageInfo = studentService.findAllByCondition(studentVo,pagesize,pagenum);
            // 返回
            return BaseResult.ok("查询成功", pageInfo);
        }
    }
    

3.1.2 添加学生

  • service

        /**
         * 添加学生
         * @param student
         * @return
         */
        public boolean save(Student student){
            // 校验
            Student find = studentMapper.selectByPrimaryKey(student.getSid());
            if(find != null) {
                throw new RuntimeException("ID已存在");
            }
            // 添加
            int count = studentMapper.insert(student);
            return count == 1;
        }
    
  • controller

        /**
         * 添加学生
         * @param student
         * @return
         */
        @PostMapping
        public BaseResult save(@RequestBody Student student){
            try {
                // 添加
                boolean result = studentService.save(student);
                // 返回
                if(result){
                    return BaseResult.ok("添加成功");
                } else {
                    return BaseResult.error("添加失败");
                }
            } catch (Exception e) {
                return BaseResult.error(e.getMessage());
            }
        }
    

3.1.3 查询学生详情

  • service

        /**
         * 查询详情
         * @param studentId
         * @return
         */
        public Student findById(String studentId){
            Student student = studentMapper.selectByPrimaryKey(studentId);
            return student;
        }
    
  • controller

        /**
         * 查询详情
         * @param studentId
         * @return
         */
        @GetMapping("/{id}")
        public BaseResult findById(@PathVariable("id") String studentId ){
            // 查询
            Student student = studentService.findById(studentId);
            if(student != null){
                // 返回
                return BaseResult.ok("查询成功", student);
            } else {
                return BaseResult.error("查询失败");
            }
        }
    

3.1.4 更新学生

  • service

        /**
         * 更新操作
         * @param student
         * @return
         */
        public boolean update(Student student){
            // 校验
            Student find = studentMapper.selectByPrimaryKey(student.getSid());
            if(find == null) {
                throw new RuntimeException("ID不存在");
            }
            // 更新非空项
            int count = studentMapper.updateByPrimaryKeySelective(student);
            return count == 1;
        } 
    
  • controller

        /**
         * 更新操作
         * @param student
         * @return
         */
        @PutMapping
        public BaseResult update(@RequestBody Student student){
            try {
                // 添加
                boolean result = studentService.update(student);
                // 返回
                if(result){
                    return BaseResult.ok("更新成功");
                } else {
                    return BaseResult.error("更新失败");
                }
            } catch (Exception e) {
                return BaseResult.error(e.getMessage());
            }
        }
    

3.1.5 删除学生

  • service

         /**
         * 通过id删除详情
         * @param studentId
         * @return
         */
        public boolean deleteById(String studentId) {
            int count = studentMapper.deleteByPrimaryKey(studentId);
            return count == 1;
        }  
    
  • controller

        /**
         * 通过id删除
         * @param studentId
         * @return
         */
        @DeleteMapping("/{id}")
        public BaseResult deleteById(@PathVariable("id") String studentId ){
            // 查询
            boolean result = studentService.deleteById(studentId);
            // 返回
            if(result){
                return BaseResult.ok("删除成功");
            } else {
                return BaseResult.error("删除失败");
            }
        }
    

4. 使用Cloud Studio 实现前端:Vue版

  • 项目前端目录结构

image-20230721161209249

  • 使用Cloud Studio 开发前端页面

Cloud Studio是一个基于Web的集成开发环境(IDE),它可以帮助开发者快速地创建和编辑前端页面。在Cloud Studio中,你可以使用HTML、CSS和JavaScript等技术来构建网页,并利用其内置的功能进行调试和优化。

以下是使用Cloud Studio开发前端页面的一些基本步骤:

  1. 打开Cloud Studio并创建一个新的项目。

  2. 在项目中创建一个新的HTML文件。你可以在文件编辑器中输入HTML代码来定义网页的结构和内容。例如,你可以添加一个标题、段落、图片等元素。

  3. 使用CSS样式表来美化网页。你可以在CSS文件中定义字体、颜色、布局等样式,并将其应用到HTML文件中的相应元素上。

  4. 添加交互功能。你可以使用JavaScript来实现网页的动态效果和交互功能。例如,你可以编写脚本来处理用户输入、响应按钮点击事件等。

  5. 调试和测试网页。在Cloud Studio中,你可以使用内置的浏览器模拟器来预览网页的效果,并检查是否存在错误或问题。如果需要进一步调试,你还可以使用Cloud Studio提供的调试工具来跟踪代码执行过程并查找问题所在。

总之,Cloud Studio是一个非常方便易用的前端开发工具,它可以帮助开发者快速地创建和管理前端页面,并提供了一系列实用的功能来提高开发效率和质量。

4.1 班级前端

4.1.1 查询所有

image-20230721164410524

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>班级列表</title>

    <script type="text/javascript" src="js/vue.js"></script>
    <script type="text/javascript" src="js/axios.js"></script>

</head>
<body>
    <div id="app">
        <a href="index.html">返回首页</a>
        <a href="classes_add.html">添加班级</a> <br/>
    
        <table id="tid" border="1" width="800">
            <tr>
                <td>班级ID</td>
                <td>班级名称</td>
                <td>班级描述</td>
                <td>操作</td>
            </tr>
            <tr v-for="(classes,index) in classesList" :key="index">
                <td>{{classes.cid}}</td>
                <td>{{classes.cname}}</td>
                <td>{{classes.desc}}</td>
                <td>
                    <a href="">修改</a>
                    <a href="">删除</a>
                </td>
            </tr>
        </table>
    </div>
</body>
</html>
<script>
        new Vue({
            el: '#app',
            data: {
                classesList: [],       //班级数据
            },
            mounted() {
                // 查询所有
                this.findAll()
            },
            methods: {
                findAll() {
                    var url = `/classes`;
                    axios.get(url)
                    .then( response => {
                        if(response.data.code == 1){
                            this.classesList = response.data.data
                        } else {
                            alert(response.data.message)
                        }
                    })
                    .catch(error => {
                        alert(error)
                    })
                }
            },
        })
    </script>

4.1.2 添加

image-20230721164352524

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>班级列表</title>

    <script type="text/javascript" src="js/vue.js"></script>
    <script type="text/javascript" src="js/axios.js"></script>

<body>
</head>
    <div id="app">
        <a href="classes_list.html">返回列表页</a>
    
        <table id="tid" border="1">
            <tr>
                <td>班级ID</td>
                <td><input v-model="classes.cid" /> </td>
            </tr>
            <tr>
                <td>班级名称</td>
                <td><input  v-model="classes.cname" /> </td>
            </tr>
            <tr>
                <td>班级描述</td>
                <td>
                    <textarea cols="20" rows="5" v-model="classes.desc" ></textarea>
                </td>
            </tr>
            <tr>
                <td></td>
                <td><input type="button" value="添加" @click="addClasses" /></td>
            </tr>
    
        </table>
    </div>
</body>
</html>
<script>
    new Vue({
        el: '#app',
        data: {
            classes: {},       //学生表单数据
        },
        mounted() {
            
        },
        methods: {
            addClasses() {
                var url = `/classes`;
                axios.post(url, this.classes)
                .then( response => {
                    if(response.data.code == 1){
                        // 成功提示
                        alert(response.data.message)
                        // 跳转
                        location.href = "classes_list.html"
                    } else {
                        alert(response.data.message)
                    }
                })
                .catch(error => {
                    alert(error)
                })
            }
        },
    })
</script>

4.1.3 修改

image-20230721164428538

  • 跳转页面

image-20201011234924215

<a :href="'classes_edit.html?id=' + classes.cid">修改</a>
  • 回显

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>班级列表</title>
    
        <script type="text/javascript" src="js/vue.js"></script>
        <script type="text/javascript" src="js/axios.js"></script>
    
    <body>
    </head>
        <div id="app">
            <a href="classes_list.html">返回列表页</a>
        
            <table id="tid" border="1">
                <tr>
                    <td>班级名称</td>
                    <td>
                        <input v-model="classes.cname" />
                    </td>
                </tr>
                <tr>
                    <td>班级描述</td>
                    <td>
                        <textarea cols="20" rows="5" v-model="classes.desc" ></textarea>
                    </td>
                </tr>
                <tr>
                    <td></td>
                    <td><input type="button" value="更新" /></td>
                </tr>
        
            </table>
        </div>
    
    </body>
    </html>
    <script>
        new Vue({
            el: '#app',
            data: {
                classes: {},       //学生表单数据
            },
            mounted() {
                // 通过id查询详情
                this.findById()
            },
            methods: {
                findById() {
                    // 获得id
                    var arr = location.href.split("?id=")
                    var id = arr[1]
                    // 路径
                    var url = `/classes/${id}`;
    
                    axios.get(url)
                    .then( response => {
                        if(response.data.code == 1){
                            this.classes = response.data.data
                        } else {
                            alert(response.data.message)
                        }
                    })
                    .catch(error => {
                        alert(error)
                    })
                }
            },
        })
    </script>
    
  • 提交

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>班级列表</title>
    
        <script type="text/javascript" src="js/vue.js"></script>
        <script type="text/javascript" src="js/axios.js"></script>
    
    <body>
    </head>
        <div id="app">
            <a href="classes_list.html">返回列表页</a>
        
            <table id="tid" border="1">
                <tr>
                    <td>班级名称</td>
                    <td>
                        <input v-model="classes.cname" />
                    </td>
                </tr>
                <tr>
                    <td>班级描述</td>
                    <td>
                        <textarea cols="20" rows="5" v-model="classes.desc" ></textarea>
                    </td>
                </tr>
                <tr>
                    <td></td>
                    <td><input type="button" value="更新" @click="editClasses" /></td>
                </tr>
        
            </table>
        </div>
    
    </body>
    </html>
    <script>
        new Vue({
            el: '#app',
            data: {
                classes: {},       //学生表单数据
            },
            mounted() {
                // 通过id查询详情
                this.findById()
            },
            methods: {
                findById() {
                    // 获得id
                    var arr = location.href.split("?id=")
                    var id = arr[1]
                    // 路径
                    var url = `/classes/${id}`;
    
                    axios.get(url)
                    .then( response => {
                        if(response.data.code == 1){
                            this.classes = response.data.data
                        } else {
                            alert(response.data.message)
                        }
                    })
                    .catch(error => {
                        alert(error)
                    })
                },
                editClasses() {
                    var url = `/classes`;
                    axios.put(url, this.classes)
                    .then( response => {
                        if(response.data.code == 1){
                            // 成功提示
                            alert(response.data.message)
                            // 跳转
                            location.href = "classes_list.html"
                        } else {
                            alert(response.data.message)
                        }
                    })
                    .catch(error => {
                        alert(error)
                    })
                }
            },
        })
    </script>
    

4.1.4 删除

  • 修改 classes_list.html 页面,填写修改功能

    image-20201013183258786

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>班级列表</title>

    <script type="text/javascript" src="js/vue.js"></script>
    <script type="text/javascript" src="js/axios.js"></script>

</head>
<body>
    <div id="app">
        <a href="index.html">返回首页</a>
        <a href="classes_add.html">添加班级</a> <br/>
    
        <table id="tid" border="1" width="800">
            <tr>
                <td>班级ID</td>
                <td>班级名称</td>
                <td>班级描述</td>
                <td>操作</td>
            </tr>
            <tr v-for="(classes,index) in classesList" :key="index">
                <td>{{classes.cid}}</td>
                <td>{{classes.cname}}</td>
                <td>{{classes.desc}}</td>
                <td>
                    <a :href="'classes_edit.html?id=' + classes.cid">修改</a>
                    <a href="#" @click="deleteClasses(classes.cid)">删除</a>
                </td>
            </tr>
        </table>
    </div>
</body>
</html>
<script>
    new Vue({
        el: '#app',
        data: {
            classesList: [],       //班级数据
        },
        mounted() {
            // 查询所有
            this.findAll()
        },
        methods: {
            findAll() {
                var url = `/classes`;
                axios.get(url)
                .then( response => {
                    if(response.data.code == 1){
                        this.classesList = response.data.data
                    } else {
                        alert(response.data.message)
                    }
                })
                .catch(error => {
                    alert(error)
                })
            },
            deleteClasses(id) {
                if(! confirm("您确定要删除么?")){
                    return 
                }
                // 删除
                var url = `/classes/${id}`;
                axios.delete(url)
                .then( response => {
                    if(response.data.code == 1){
                        // 成功提示
                        alert(response.data.message)
                        // 跳转
                        location.href = "classes_list.html"
                    } else {
                        alert(response.data.message)
                    }
                })
                .catch(error => {
                    alert(error)
                })
            }
        },
    })
</script>

4.2 学生前端

4.2.1 查询所有

1)查询 + 条件 + 分页

image-20230721164452402

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>班级列表</title>

    <script type="text/javascript" src="js/vue.js"></script>
    <script type="text/javascript" src="js/axios.js"></script>

</head>
<body>
    <div id="app">
        <a href="index.html">返回首页</a>
        <a href="student_add.html">添加学生</a> <br/>
        <!-- 查询条件 -->
        <table>
            <tr>
                <td>班级</td>
                <td>
                    <select v-model="student.cid">
                        <option value="">--选择班级--</option>
                        <option value="c001">--Java12--</option>
                        <option value="c002">--Java34--</option>
                    </select>
                </td>
                <td>姓名:</td>
                <td>
                    <input type="text" placeholder="请输入姓名" v-model="student.sname"size="10">
                </td>
                <td>年龄:</td>
                <td>
                    <input type="text" placeholder="请输入开始年龄" v-model="student.startAge" size="10">
                    --
                    <input type="text" placeholder="请输入结束年龄" v-model="student.endAge" size="10">
                </td>
                <td><input type="button" value="查询" @click="condition(1)"></td>
            </tr>
        </table>
        
        <!-- 查询列表 -->
        <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.classes.cname}}</td>
                <td>{{student.sname}}</td>
                <td>{{student.age}}</td>
                <td>{{student.birthday}}</td>
                <td>{{student.gender == 1 ? "男" : "女"}}</td>
                <td>
                    <a href="">修改</a>
                    <a href="">删除</a>
                </td>
            </tr>
        </table>
    
        <!-- 分页条 -->
        <div id="pageId">
            <a href="#" v-for="index in pageInfo.pages" :key="index" @click.prevent="condition(index)" >{{index}}</a> 
        </div>

    </div>
</body>
</html>
<script>
    new Vue({
        el: '#app',
        data: {
            pageSize: 2,        //每页多少条
            student: {          //表单对象

            },
            pageInfo: {},       //分页对象
        },
        mounted() {
            // 查询所有
            this.condition(1)
        },
        methods: {
            condition(pageNum) {
                var url = `/student/condition/${this.pageSize}/${pageNum}`;
                axios.post(url, this.student)
                .then( response => {
                    if(response.data.code == 1){
                        this.pageInfo = response.data.data
                    } else {
                        alert(response.data.message)
                    }
                })
                .catch(error => {
                })
            }
        },
    })
</script>
2)查询条件,下拉列表

image-20230721164518224

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>班级列表</title>

    <script type="text/javascript" src="js/vue.js"></script>
    <script type="text/javascript" src="js/axios.js"></script>

</head>
<body>
    <div id="app">
        <a href="index.html">返回首页</a>
        <a href="student_add.html">添加学生</a> <br/>
        <!-- 查询条件 -->
        <table>
            <tr>
                <td>班级</td>
                <td>
                    <select v-model="student.cid">
                        <option value="">--选择班级--</option>
                        <option v-for="(classes,index) in classesList" :key="index" :value="classes.cid">{{classes.cname}}</option>
                    </select>
                </td>
                <td>姓名:</td>
                <td>
                    <input type="text" placeholder="请输入姓名" v-model="student.sname"size="10">
                </td>
                <td>年龄:</td>
                <td>
                    <input type="text" placeholder="请输入开始年龄" v-model="student.startAge" size="10">
                    --
                    <input type="text" placeholder="请输入结束年龄" v-model="student.endAge" size="10">
                </td>
                <td><input type="button" value="查询" @click="condition(1)"></td>
            </tr>
        </table>

        <!-- 查询列表 -->
        <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.classes.cname}}</td>
                <td>{{student.sname}}</td>
                <td>{{student.age}}</td>
                <td>{{student.birthday}}</td>
                <td>{{student.gender == 1 ? "男" : "女"}}</td>
                <td>
                    <a href="">修改</a>
                    <a href="">删除</a>
                </td>
            </tr>
        </table>
    
        <!-- 分页条 -->
        <div id="pageId">
            <a href="#" v-for="index in pageInfo.pages" :key="index" @click.prevent="condition(index)" >{{index}}</a> 
        </div>

    </div>
</body>
</html>
<script>
    new Vue({
        el: '#app',
        data: {
            pageSize: 2,        //每页多少条
            student: {          //表单对象
                cid: ''
            },
            pageInfo: {},       //分页对象
            classesList: []     //班级列表
        },
        mounted() {
            // 查询所有
            this.condition(1)
            // 查询所有班级
            this.findAllClasses()
        },
        methods: {
            condition(pageNum) {
                var url = `/student/condition/${this.pageSize}/${pageNum}`;
                axios.post(url, this.student)
                .then( response => {
                    if(response.data.code == 1){
                        this.pageInfo = response.data.data
                    } else {
                        alert(response.data.message)
                    }
                })
                .catch(error => {
                })
            },
            findAllClasses() {
                var url = `/classes`;
                axios.get(url)
                .then( response => {
                    if(response.data.code == 1){
                        this.classesList = response.data.data
                    } else {
                        alert(response.data.message)
                    }
                })
                .catch(error => {
                    alert(error)
                })
            }
        },
    })
</script>
3)跳转
image-20230721164558972
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>班级列表</title>

    <script type="text/javascript" src="js/vue.js"></script>
    <script type="text/javascript" src="js/axios.js"></script>

</head>
<body>
    <div id="app">
        <a href="index.html">返回首页</a>
        <a href="student_add.html">添加学生</a> <br/>
        <!-- 查询条件 -->
        <table>
            <tr>
                <td>班级</td>
                <td>
                    <select v-model="student.cid">
                        <option value="">--选择班级--</option>
                        <option v-for="(classes,index) in classesList" :key="index" :value="classes.cid">{{classes.cname}}</option>
                    </select>
                </td>
                <td>姓名:</td>
                <td>
                    <input type="text" placeholder="请输入姓名" v-model="student.sname"size="10">
                </td>
                <td>年龄:</td>
                <td>
                    <input type="text" placeholder="请输入开始年龄" v-model="student.startAge" size="10">
                    --
                    <input type="text" placeholder="请输入结束年龄" v-model="student.endAge" size="10">
                </td>
                <td><input type="button" value="查询" @click="condition(1)"></td>
            </tr>
        </table>

        <!-- 查询列表 -->
        <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.classes.cname}}</td>
                <td>{{student.sname}}</td>
                <td>{{student.age}}</td>
                <td>{{student.birthday}}</td>
                <td>{{student.gender == 1 ? "男" : "女"}}</td>
                <td>
                    <a href="">修改</a>
                    <a href="">删除</a>
                </td>
            </tr>
        </table>
    
        <!-- 分页条 -->
        <div id="pageId">
            <a href="#" v-for="index in pageInfo.pages" :key="index" @click.prevent="condition(index)" >{{index}}</a> 
            跳转到第 <input type="text" v-model="pageNum" size="5" @keydown.enter="go" /></div>

    </div>
</body>
</html>
<script>
    new Vue({
        el: '#app',
        data: {
            pageSize: 2,        //每页多少条
            pageNum: 1,         //第几页
            student: {          //表单对象
                cid: ''
            },
            pageInfo: {},       //分页对象
            classesList: []     //班级列表
        },
        mounted() {
            // 查询所有
            this.condition(1)
            // 查询所有班级
            this.findAllClasses()
        },
        methods: {
            condition(pageNum) {
                var url = `/student/condition/${this.pageSize}/${pageNum}`;
                axios.post(url, this.student)
                .then( response => {
                    if(response.data.code == 1){
                        this.pageInfo = response.data.data
                    } else {
                        alert(response.data.message)
                    }
                })
                .catch(error => {
                })
            },
            findAllClasses() {
                var url = `/classes`;
                axios.get(url)
                .then( response => {
                    if(response.data.code == 1){
                        this.classesList = response.data.data
                    } else {
                        alert(response.data.message)
                    }
                })
                .catch(error => {
                    alert(error)
                })
            },
            go() {
                if(parseInt(this.pageNum) == this.pageNum) {
                    this.condition(this.pageNum)
                }
            }
        },
    })
</script>
4)改变分页pageSize

image-20230721170107387

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>班级列表</title>

    <script type="text/javascript" src="js/vue.js"></script>
    <script type="text/javascript" src="js/axios.js"></script>

</head>
<body>
    <div id="app">
        <a href="index.html">返回首页</a>
        <a href="student_add.html">添加学生</a> <br/>
        <!-- 查询条件 -->
        <table>
            <tr>
                <td>班级</td>
                <td>
                    <select v-model="student.cid">
                        <option value="">--选择班级--</option>
                        <option v-for="(classes,index) in classesList" :key="index" :value="classes.cid">{{classes.cname}}</option>
                    </select>
                </td>
                <td>姓名:</td>
                <td>
                    <input type="text" placeholder="请输入姓名" v-model="student.sname"size="10">
                </td>
                <td>年龄:</td>
                <td>
                    <input type="text" placeholder="请输入开始年龄" v-model="student.startAge" size="10">
                    --
                    <input type="text" placeholder="请输入结束年龄" v-model="student.endAge" size="10">
                </td>
                <td><input type="button" value="查询" @click="condition(1)"></td>
            </tr>
        </table>

        <!-- 查询列表 -->
        <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.classes.cname}}</td>
                <td>{{student.sname}}</td>
                <td>{{student.age}}</td>
                <td>{{student.birthday}}</td>
                <td>{{student.gender == 1 ? "男" : "女"}}</td>
                <td>
                    <a href="">修改</a>
                    <a href="">删除</a>
                </td>
            </tr>
        </table>
    
        <!-- 分页条 -->
        <div id="pageId">
            每页
            <select v-model="pageSize" @change="condition(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="condition(index)" >{{index}}</a> 
            ,跳转到第 <input type="text" v-model="pageNum" size="5" @keydown.enter="go" /></div>

    </div>
</body>
</html>
<script>
    new Vue({
        el: '#app',
        data: {
            pageSize: 2,        //每页多少条
            pageNum: 1,         //第几页
            student: {          //表单对象
                cid: ''
            },
            pageInfo: {},       //分页对象
            classesList: []     //班级列表
        },
        mounted() {
            // 查询所有
            this.condition(1)

            // 查询所有班级
            this.findAllClasses()
        },
        methods: {
            condition(pageNum) {
                var url = `/student/condition/${this.pageSize}/${pageNum}`;
                axios.post(url, this.student)
                .then( response => {
                    if(response.data.code == 1){
                        this.pageInfo = response.data.data
                    } else {
                        alert(response.data.message)
                    }
                })
                .catch(error => {
                })
            },
            findAllClasses() {
                var url = `/classes`;
                axios.get(url)
                .then( response => {
                    if(response.data.code == 1){
                        this.classesList = response.data.data
                    } else {
                        alert(response.data.message)
                    }
                })
                .catch(error => {
                    alert(error)
                })
            },
            go() {
                if(parseInt(this.pageNum) == this.pageNum) {
                    this.condition(this.pageNum)
                }
            }
        },
    })
</script>

4.2.2 添加

image-20230721170039165

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>班级列表</title>

    <script type="text/javascript" src="js/vue.js"></script>
    <script type="text/javascript" src="js/axios.js"></script>

<body>
</head>
    <div id="app">

        <a href="student_list.html">返回列表页</a>
    
        <table id="tid" border="1">
            <tr>
                <td>学生</td>
                <td><input v-model="student.sid" /> </td>
            </tr>
            <tr>
                <td>班级ID</td>
                <td>
                    <!-- <input name="cId" /> -->
                    <select v-model="student.cid">
                        <option value="">--请选择--</option>
                        <option v-for="(classes,index) in classesList" :key="index" :value="classes.cid">{{classes.cname}}</option>
                    </select>
                </td>
            </tr>
            <tr>
                <td>姓名</td>
                <td><input v-model="student.sname"/> </td>
            </tr>
            <tr>
                <td>年龄</td>
                <td><input v-model="student.age" /> </td>
            </tr>
            <tr>
                <td>生日</td>
                <td><input v-model="student.birthday"/> </td>
            </tr>
            <tr>
                <td>性别</td>
                <td>
                    <input type="radio" v-model="student.gender" value="1" /><input type="radio" v-model="student.gender" value="0" /></td>
            </tr>
            <tr>
                <td></td>
                <td><input type="button" value="添加" @click="addStudent"/></td>
            </tr>

        </table>
    </div>
</body>
</html>
<script>
    new Vue({
        el: '#app',
        data: {
            student: {          //表单对象
                cid: ''
            },
            classesList: []     //班级列表
        },
        mounted() {

            // 查询所有班级
            this.findAllClasses()
        },
        methods: {

            findAllClasses() {
                var url = `/classes`;
                axios.get(url)
                .then( response => {
                    if(response.data.code == 1){
                        this.classesList = response.data.data
                    } else {
                        alert(response.data.message)
                    }
                })
                .catch(error => {
                    alert(error)
                })
            },
            addStudent() {
                var url = `/student`;
                axios.post(url, this.student)
                .then( response => {
                    if(response.data.code == 1){
                        // 成功提示
                        alert(response.data.message)
                        // 跳转
                        location.href = "student_list.html"
                    } else {
                        alert(response.data.message)
                    }
                })
                .catch(error => {
                    alert(error)
                })
            },

        },
    })
</script>

4.2.3 修改

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>编辑学生</title>

    <script type="text/javascript" src="js/vue.js"></script>
    <script type="text/javascript" src="js/axios.js"></script>

<body>
</head>
<div id="app">

    <a href="student_list.html">返回列表页</a>

    <table id="tid" border="1">
        <tr>
            <td>学生</td>
            <td><input v-model="student.sid" /> </td>
        </tr>
        <tr>
            <td>班级ID</td>
            <td>
                <!-- <input name="cId" /> -->
                <select v-model="student.cid">
                    <option value="">--请选择--</option>
                    <option v-for="(classes,index) in classesList" :key="index" :value="classes.cid">{{classes.cname}}</option>
                </select>
            </td>
        </tr>
        <tr>
            <td>姓名</td>
            <td><input v-model="student.sname"/> </td>
        </tr>
        <tr>
            <td>年龄</td>
            <td><input v-model="student.age" /> </td>
        </tr>
        <tr>
            <td>生日</td>
            <td><input v-model="student.birthday"/> </td>
        </tr>
        <tr>
            <td>性别</td>
            <td>
                <input type="radio" v-model="student.gender" value="1" /><input type="radio" v-model="student.gender" value="0" /></td>
        </tr>
        <tr>
            <td></td>
            <td><input type="button" value="添加" @click="editStudent"/></td>
        </tr>

    </table>
</div>
</body>
</html>
<script>
    new Vue({
        el: '#app',
        data: {
            student: {          //表单对象
                cid: ''
            },
            classesList: []     //班级列表
        },
        mounted() {

            // 查询所有班级
            this.findAllClasses()
        },
        methods: {

            findAllClasses() {
                var url = `/classes`;
                axios.get(url)
                .then( response => {
                    if(response.data.code == 1){
                        this.classesList = response.data.data
                        // 查询详情
                        this.findById()
                    } else {
                        alert(response.data.message)
                    }
                })
                .catch(error => {
                    alert(error)
                })
            },
            findById() {
                // 获得id
                var arr = location.href.split("?id=")
                var id = arr[1]
                // 路径
                var url = `/student/${id}`;

                axios.get(url)
                .then( response => {
                    if(response.data.code == 1){
                        this.student = response.data.data
                    } else {
                        alert(response.data.message)
                    }
                })
                .catch(error => {
                    alert(error)
                })
            },
            editStudent() {
                var url = `/student`;
                axios.put(url, this.student)
                .then( response => {
                    if(response.data.code == 1){
                        // 成功提示
                        alert(response.data.message)
                        // 跳转
                        location.href = "student_list.html"
                    } else {
                        alert(response.data.message)
                    }
                })
                .catch(error => {
                    alert(error)
                })
            },

        },
    })
</script>

4.2.4 删除

image-20230721170000466

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>班级列表</title>

    <script type="text/javascript" src="js/vue.js"></script>
    <script type="text/javascript" src="js/axios.js"></script>

</head>
<body>
<div id="app">
    <a href="index.html">返回首页</a>
    <a href="student_add.html">添加学生</a> <br/>
    <!-- 查询条件 -->
    <table>
        <tr>
            <td>班级</td>
            <td>
                <select v-model="student.cid">
                    <option value="">--选择班级--</option>
                    <option v-for="(classes,index) in classesList" :key="index" :value="classes.cid">{{classes.cname}}</option>
                </select>
            </td>
            <td>姓名:</td>
            <td>
                <input type="text" placeholder="请输入姓名" v-model="student.sname"size="10">
            </td>
            <td>年龄:</td>
            <td>
                <input type="text" placeholder="请输入开始年龄" v-model="student.startAge" size="10">
                --
                <input type="text" placeholder="请输入结束年龄" v-model="student.endAge" size="10">
            </td>
            <td><input type="button" value="查询" @click="condition(1)"></td>
        </tr>
    </table>

    <!-- 查询列表 -->
    <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.classes.cname}}</td>
            <td>{{student.sname}}</td>
            <td>{{student.age}}</td>
            <td>{{student.birthday}}</td>
            <td>{{student.gender == 1 ? "男" : "女"}}</td>
            <td>
                <a :href="'student_edit.html?id='+student.sid">修改</a>
                <a href="#" @click.prevent="deleteStudent(student.sid)">删除</a>
            </td>
        </tr>
    </table>

    <!-- 分页条 -->
    <div id="pageId">
        每页
        <select v-model="pageSize" @change="condition(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="condition(index)" >{{index}}</a>
        ,跳转到第 <input type="text" v-model="pageNum" size="5" @keydown.enter="go" /></div>

</div>
</body>
</html>
<script>
    new Vue({
        el: '#app',
        data: {
            pageSize: 2,        //每页多少条
            pageNum: 1,         //第几页
            student: {          //表单对象
                cid: ''
            },
            pageInfo: {},       //分页对象
            classesList: []     //班级列表
        },
        mounted() {
            // 查询所有
            this.condition(1)
            this.condition(1)
            this.condition(1)
            this.condition(1)
            // 查询所有班级
            this.findAllClasses()
        },
        methods: {
            condition(pageNum) {
                var url = `/student/condition/${this.pageSize}/${pageNum}`;
                axios.post(url, this.student)
                    .then( response => {
                        if(response.data.code == 1){
                            this.pageInfo = response.data.data
                        } else {
                            alert(response.data.message)
                        }
                    })
                    .catch(error => {
                    })
            },
            findAllClasses() {
                var url = `/classes`;
                axios.get(url)
                    .then( response => {
                        if(response.data.code == 1){
                            this.classesList = response.data.data
                        } else {
                            alert(response.data.message)
                        }
                    })
                    .catch(error => {
                        alert(error)
                    })
            },
            go() {
                if(parseInt(this.pageNum) == this.pageNum) {
                    this.condition(this.pageNum)
                }
            },
            deleteStudent(id) {
                if(! confirm("您确定要删除么?")){
                    return
                }
                // 删除
                var url = `/student/${id}`;
                axios.delete(url)
                    .then( response => {
                        if(response.data.code == 1){
                            // 成功提示
                            alert(response.data.message)
                            // 跳转
                            location.href = "student_list.html"
                        } else {
                            alert(response.data.message)
                        }
                    })
                    .catch(error => {
                        alert(error)
                    })
            }
        },
    })
</script>

5. 用户操作

5.1 建表语句

create table tb_user(
  u_id varchar(32) primary key comment '用户编号',
  user_name varchar(50) comment '用户名',
  password varchar(32) comment '密码',
  gender bit comment '性别,1表示男,0表示女'
);
insert into tb_user(u_id,user_name,password,gender) values('u001','jack','1234',1);
insert into tb_user(u_id,user_name,password,gender) values('u002','rose','1234',0);
insert into tb_user(u_id,user_name,password,gender) values('u003','张三','1234',1);

5.2 后端实现:domain、mapper

  • domain

    package com.czxy.domain;
    
    import javax.persistence.Column;
    import javax.persistence.Id;
    import javax.persistence.Table;
    
    /**
     * @author manor
     *  
     */
    @Table(name = "tb_user")
    public class User {
        @Id
        @Column(name = "u_id")
        private String uid;         //用户编号
    
        @Column(name = "user_name")
        private String username;     //用户名
    
        @Column(name = "password")
        private String password;         //密码
    
        @Column(name = "gender")
        private Integer gender;         //性别,1表示男,0表示女
    
        public String getUid() {
            return uid;
        }
    
        public void setUid(String uid) {
            this.uid = uid;
        }
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        public Integer getGender() {
            return gender;
        }
    
        public void setGender(Integer gender) {
            this.gender = gender;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "uid='" + uid + '\'' +
                    ", username='" + username + '\'' +
                    ", password='" + password + '\'' +
                    ", gender=" + gender +
                    '}';
        }
    }
    
    
    
  • mapper

    package com.czxy.mapper;
    
    import com.czxy.domain.User;
    import tk.mybatis.mapper.common.Mapper;
    
    /**
     * @author manor
     *  
     */
    @org.apache.ibatis.annotations.Mapper
    public interface UserMapper extends Mapper<User> {
    }
    
    

5.3 用户注册

5.3.1 分析

  • 用户注册,其实就是添加功能

image-20230721165914778

5.3.2 后端实现

  • 编写service,用户名存在不允许注册

package com.czxy.service;

import com.czxy.domain.User;
import com.czxy.mapper.UserMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;

/**

  • @author manor

*/
@Service
@Transactional
public class UserService {

  @Resource
  private UserMapper userMapper;

  /**
   * 用户注册
   * @param user
   * @return
   */
  public boolean register(User user){
      // 校验:用户名
      User findUser = findByUsername(user.getUsername());
      if(findUser != null){
          throw new RuntimeException("用户名已存在");
      }

      // 添加
      int count = userMapper.insert(user);

      // 返回
      return count == 1;
  }

  /**
   * 通过用户名查询
   * @param username
   * @return
   */
  public User findByUsername(String username){
      // 拼凑条件
      Example example = new Example(User.class);
      Example.Criteria criteria = example.createCriteria();
      criteria.andEqualTo("username", username);

      // 查询
      User user = userMapper.selectOneByExample(example);
      return user;
  }

}




* 编写controller



~~~java
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.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * @author manor
 *  
 */
@RestController
@RequestMapping("/user")
public class UserController {

    @Resource
    private UserService userService;

    /**
     * 用户注册
     * @param user
     * @return
     */
    @PostMapping("/register")
    public BaseResult register(@RequestBody User user) {
        try {
            // 注册
            boolean result = userService.register(user);

            // 返回
            if(result){
                return BaseResult.ok("注册成功");
            } else {
                return BaseResult.error("注册失败");
            }
        } catch (Exception e) {
            return BaseResult.error(e.getMessage());
        }
    }

}

5.3.3 前端实现

  • 修改首页,跳转到注册页面

    image-20201012113021509

<a href="user_register.html">注册</a> |
  • 编写注册功能:注册成功跳转到首页
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用户注册</title>

    <script type="text/javascript" src="js/vue.js"></script>
    <script type="text/javascript" src="js/axios.js"></script>

<body>
</head>
    <div id="app">
        <a href="index.html">返回首页</a>
    
        <table id="tid" border="1">
            <tr>
                <td>用户名</td>
                <td><input v-model="user.username" /> </td>
            </tr>
            <tr>
                <td>密码</td>
                <td><input type="password" v-model="user.password" /> </td>
            </tr>
            <tr>
                <td>性别</td>
                <td>
                    <input type="radio" v-model="user.gender" value="1"><input type="radio" v-model="user.gender" value="0"></td>
            </tr>
            <tr>
                <td></td>
                <td><input type="button" value="注册" @click="register" /></td>
            </tr>
    
        </table>
    </div>
</body>
</html>
<script>
    new Vue({
        el: '#app',
        data: {
            user: {},       //用户表单数据
        },
        methods: {
            register() {
                var url = `/user/register`;
                axios.post(url, this.user)
                .then( response => {
                    if(response.data.code == 1){
                        // 成功提示
                        alert(response.data.message)
                        // 跳转
                        location.href = "index.html"
                    } else {
                        alert(response.data.message)
                    }
                })
                .catch(error => {
                    alert(error)
                })
            }
        },
    })
</script>

5.4 用户登录

5.4.1 分析

  • 用户登录,也是就是一个通过用户名和密码的查询功能

5.4.2 后端实现

  • 修改service,添加login方法

    image-20230721165850462

    /**
         * 用户登录
         * @param user
         * @return
         */
        public User login (User user){
            // 校验:用户名
            User findUser = findByUsername(user.getUsername());
            if(findUser == null){
                throw new RuntimeException("用户名不存在");
            }
    
            // 登录条件
            Example example = new Example(User.class);
            Example.Criteria criteria = example.createCriteria();
            criteria.andEqualTo("username", user.getUsername());
            criteria.andEqualTo("password", user.getPassword());
    
            // 查询
            User loginUser = userMapper.selectOneByExample(example);
            return loginUser;
        }
    
  • 修改controller,添加login 方法

        /**
         * 用户注册
         * @param user
         * @return
         */
        @PostMapping("/login")
        public BaseResult login(@RequestBody User user) {
            try {
                // 注册
                User loginUser = userService.login(user);
    
                // 返回
                if(loginUser != null ){
                    // 需要将用户信息响应给浏览器
                    return BaseResult.ok("登录成功", loginUser);
                } else {
                    return BaseResult.error("用户名或密码不匹配");
                }
            } catch (Exception e) {
                return BaseResult.error(e.getMessage());
            }
        }
    

5.4.3 localStorage&sessionStorage详解

  • localStorage和sessionStorage都是window对象提供的全局属性,在浏览器中存储key/value对的数据
    • localStorage,本地存储,浏览器窗口关闭后,数据保留
    • sessionStorage,会话存储,浏览器窗口关闭后,数据删除
  • 基本操作:存储数据、查询数据、删除数据
功能实例
localStorage存储数据localStorage.setItem(“键”,“值”)
查询数据localStorage.getItem(“键”)
删除数据localStorage.removeItem(“键”)
sessionStorage存储数据sessionStorage.setItem(“键”,“值”)
查询数据sessionStorage.getItem(“键”)
删除数据sessionStorage.removeItem(“键”)

5.4.4 前端实现

  • 修改首页

    image-20201012114341199

    <a href="user_login.html">注册</a> |
    
  • 编写登录页面

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>用户登录</title>
    
        <script type="text/javascript" src="js/vue.js"></script>
        <script type="text/javascript" src="js/axios.js"></script>
    
    <body>
    </head>
        <div id="app">
            <a href="index.html">返回首页</a>
        
            <table id="tid" border="1">
                <tr>
                    <td>用户名</td>
                    <td><input v-model="user.username" /> </td>
                </tr>
                <tr>
                    <td>密码</td>
                    <td><input type="password" v-model="user.password" /> </td>
                </tr>
                <tr>
                    <td></td>
                    <td><input type="button" value="登录" @click="login" /></td>
                </tr>
        
            </table>
        </div>
    </body>
    </html>
    <script>
        new Vue({
            el: '#app',
            data: {
                user: {},       //用户表单数据
            },
            methods: {
                login() {
                    var url = `/user/login`;
                    axios.post(url, this.user)
                    .then( response => {
                        if(response.data.code == 1){
                            // 成功提示
                            alert(response.data.message)
                            // 将用户信息记录到浏览器
                            var userStr = JSON.stringify(response.data.data)
                            localStorage.setItem("loginUser", userStr)
                            // 跳转
                            location.href = "index.html"
                        } else {
                            alert(response.data.message)
                        }
                    })
                    .catch(error => {
                        alert(error)
                    })
                }
            },
        })
    </script>
    

5.4.5 首页优化

  • 修改index.html页面

    image-20230721164807841

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
    <script type="text/javascript" src="js/vue.js"></script>
</head>
<body>
    <div id="app">
        <a href="classes_list.html">班级管理</a> |
        <a href="student_list.html">学生管理</a> |
        <span v-if="loginUser != null">
            <!-- 登录后显示内容 -->
            欢迎 {{loginUser.username}} ,
            <a href="#">退出</a> |
        </span>
        <span v-if="loginUser == null">
            <!-- 登录前显示内容 -->
            <a href="user_register.html">注册</a> |
            <a href="user_login.html">登录</a> |
        </span>
    </div>
    
</body>
</body>
</html>
<script>
    new Vue({
        el: '#app',
        data: {
            loginUser: null,       //登录用户信息
        },
        mounted() {
            var userStr = localStorage.getItem("loginUser")
            if(userStr){
                this.loginUser = JSON.parse(userStr)
            }
        },
        
    })
</script>

5.5 用户注销

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
    <script type="text/javascript" src="js/vue.js"></script>
</head>
<body>
    <div id="app">
        <a href="classes_list.html">班级管理</a> |
        <a href="student_list.html">学生管理</a> |
        <span v-if="loginUser != null">
            <!-- 登录后显示内容 -->
            欢迎 {{loginUser.username}} ,
            <a href="#" @click.prevent="logout">退出</a> |
        </span>
        <span v-if="loginUser == null">
            <!-- 登录前显示内容 -->
            <a href="user_register.html">注册</a> |
            <a href="user_login.html">登录</a> |
        </span>
    </div>
    
</body>
</body>
</html>
<script>
    new Vue({
        el: '#app',
        data: {
            loginUser: null,       //登录用户信息
        },
        mounted() {
            var userStr = localStorage.getItem("loginUser")
            if(userStr){
                this.loginUser = JSON.parse(userStr)
            }
        },
        methods: {
            logout() {
                localStorage.removeItem("loginUser")
                location.href = "index.html"
            }
        },
        
    })
</script>

5.6 用户注册前校验

5.6.1 分析

image-20230721164739297

image-20230721164726612

image-20230721164716889

5.6.2 后端实现

  • 修改 UserController
   /**
     * 用户名校验
     * @param user
     * @return
     */
    @PostMapping("/checkname")
    public BaseResult checkname(@RequestBody User user) {
        try {
            // 注册
            User findUser = userService.findByUsername(user.getUsername());

            // 返回
            if(findUser == null ){
                return BaseResult.ok("用户名可用");
            } else {
                return BaseResult.error("用户名不可用");
            }
        } catch (Exception e) {
            return BaseResult.error(e.getMessage());
        }
    }

5.6.3 前端实现

  • 修改注册页面
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用户注册</title>

    <script type="text/javascript" src="js/vue.js"></script>
    <script type="text/javascript" src="js/axios.js"></script>

    <style>
        .red {
            color: red;
        }
        .green {
            color: green;
        }
    </style>

<body>
</head>
<div id="app">
    <a href="index.html">返回首页</a>

    <table id="tid" border="1">
        <tr>
            <td>用户名</td>
            <td>
                <input v-model="user.username" @blur="checkname" />
                <span :class="{'red': result.code == 0,'green': result.code == 1}" >{{result.message}}</span>
            </td>
        </tr>
        <tr>
            <td>密码</td>
            <td><input type="password" v-model="user.password" /> </td>
        </tr>
        <tr>
            <td>性别</td>
            <td>
                <input type="radio" v-model="user.gender" value="1"><input type="radio" v-model="user.gender" value="0"></td>
        </tr>
        <tr>
            <td></td>
            <td><input type="button" :disabled="result.code==0" value="注册" @click="register" /></td>
        </tr>

    </table>
</div>
</body>
</html>
<script>
    new Vue({
        el: '#app',
        data: {
            user: {},       //用户表单数据
            result: {       //查询结果
                code: 0
            }      
        },
        methods: {
            register() {
                var url = `/user/register`;
                axios.post(url, this.user)
                .then( response => {
                    if(response.data.code == 1){
                        // 成功提示
                        alert(response.data.message)
                        // 跳转
                        location.href = "index.html"
                    } else {
                        alert(response.data.message)
                    }
                })
                .catch(error => {
                    alert(error)
                })
            },
            checkname() {
                var url = `/user/checkname`;
                axios.post(url, this.user)
                .then( response => {
                    // 记录查询结果
                    this.result = response.data
                })
                .catch(error => {
                    alert(error)
                })
            }
        },
    })
</script>

项目总结

选择Cloud Studio作为开发平台,省去了很多环境配置和运维的工作。通过其可视化编程和智能辅助功能,大大提高了开发效率。使用Vue.js构建界面与交互逻辑非常快速愉悦。接入云函数和数据库,可以零门槛实现服务器程序。以前需要自部署服务器,现在完全不需要,云端一切就绪。

Spring Boot框架的快速开发体验也让人眼前一亮。自动配置、起步依赖、统一配置、Actuator监控等特性可以显著减少样板代码。用Spring Security实现登录权限也很顺手,数据库访问用MyBatis也节省了很多功夫。

当然在开发中也遇到些难点。如何划分模块,前后端分工合作都是需要思考的。一些复杂业务场景的处理需要细致设计。还有就是测试case的准备以及各种异常情况的处理。这些都让我对工程能力有了更高的要求。

总体而言,通过这个项目对现代Web开发流程有了更直观的感受。也对自己的编程思维模式有了新的提高。接下来还会继续丰富完善系统功能,比如移动端支持、代码重构等。感谢各位的支持,也欢迎继续交流讨论,共同进步!

github项目链接

https://github.com/xianyu110/exam-student-vue/blob/master/README.md

体验下来的感受

我使用GPT+Cloud Studio的「念咒编程」功能,构建了一个Excel工资表自动核算的应用,现在来分享一下具体的使用体验。

首先,我准备了一个Excel工资表,包含了员工的基本信息、出勤情况、绩效等数据。为了实现自动计算工资,我需要编写一个程序来读取Excel数据,并根据设定的算法计算出工资结果。

在Cloud Studio中,我启用了GPT念咒编程功能,然后在编辑器里输入:

读取Excel表格数据,循环遍历每行,按以下规则计算工资:
基础工资2000元
每天出勤奖励50元  
绩效评级A奖励1000元,评级B奖励500元
计算结果写入新列“实发工资”

非常惊喜的是,GPT立即生成了相应的Python代码,实现了我描述的工资计算规则。我只需要点击运行,它就可以自动读取Excel,遍历计算每一行的工资,并输出结果。

tempImage1689933237024

在这过程中,我甚至不需要编写任何代码,只需要用自然语言描述业务规则,GPT就可以帮我自动转换为可执行的程序。这极大地降低了开发难度,提升了工作效率。

另外,Cloud Studio为程序提供了完善的运行时环境,包括数据存储、网络服务等资源。我可以方便地读取上传的Excel文件,并在云端执行程序。

总的来说,GPT+Cloud Studio实现了“说人话”的编程方式,让我感受到了人工智能为开发者带来的强大价值。它极大地简化了开发流程,使程序员可以更专注于业务。我相信随着AI技术的进一步进步,这种智能编程方式必将得到更广泛的应用。

image-20230721175155950

建议与方向

作为一名开发者,我有幸体验了腾讯云的Cloud Studio,并对其功能和性能有了深刻的认识。在这篇文章中,我将分享我的使用体验和感受,并提供一些建议和方向。

首先,腾讯云的Cloud Studio是一款基于云端的开发环境,提供了代码编辑、运行、部署等全套开发工具,支持多种编程语言和框架,包括Java、Python、Node.js等。同时,它还提供了丰富的插件和扩展功能,可以帮助开发者更高效地完成开发任务。

在使用过程中,我发现Cloud Studio的界面简洁明了,操作便捷流畅。特别是在代码编辑方面,它的智能感知和自动补全功能让我感到非常惊喜。不仅如此,它还支持实时预览和调试,可以快速定位和解决问题。

除此之外,Cloud Studio还提供了强大的版本控制和管理功能。它支持Git和SSH协议,可以方便地进行代码管理和协作开发。同时,它还提供了自动化部署和回滚功能,可以快速部署应用程序到云端或服务器上。

tempImage1689933315693

总的来说,腾讯云的Cloud Studio是一款非常优秀的开发工具,具有高效、便捷、安全等特点。在使用中,我也发现了一些可以改进的地方:例如,希望能够增加一些高级功能和特性,以满足更加复杂的开发需求;同时也希望能够提供更加完善的技术支持和服务,帮助开发者更好地解决各种问题。

最后,我想说的是,腾讯云的Cloud Studio是一款非常值得推荐的开发工具。如果你是一名开发者或者想要学习编程的话,不妨来用用看,反正有5000分钟的免费额度!

image-20230721174856812

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐