Web全栈开发 上机实操 - 代码汇总(补全部分标注版)

Web全栈开发 上机实操卷 - 代码汇总

颜色说明:
原有代码(题目提供的模板)
补全的代码(需要填写的部分)
按钮说明: - 复制整个代码块(原有+补全) - 只复制标记为"补全"的代码部分 - 下载单个文件

目录

第一大题:Spring Boot + MyBatis 学生管理接口 (60分)

1.1 Student 实体类 (6分)

说明:补全 @Data 注解和4个私有字段。
Student.java
package com.ch.lab.entity;

import lombok.Data;

@Data
public class Student {
    private Integer sid;
    private String sname;
    private String sgender;
    private Integer sage;
}

1.2 StudentMapper.xml SQL映射 (24分)

说明:原有文件只有 mapper 标签和 TODO 占位符。补全部分:resultMap + 7个SQL语句(select/insert/update/delete)。
StudentMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ch.lab.repository.StudentRepository">

    <resultMap id="StudentResultMap" type="Student">
        <id property="sid" column="sid"/>
        <result property="sname" column="sname"/>
        <result property="sgender" column="sgender"/>
        <result property="sage" column="sage"/>
    </resultMap>

    <!-- 1. 查询所有学生 -->
    <select id="findAll" resultMap="StudentResultMap">
        SELECT sid, sname, sgender, sage FROM student
    </select>

    <!-- 2. 条件查询(where + if 动态SQL) -->
    <select id="selectByCondition" parameterType="Student" resultMap="StudentResultMap">
        SELECT sid, sname, sgender, sage FROM student
        <where>
            <if test="sname != null and sname != ''">
                AND sname LIKE CONCAT('%', #{sname}, '%')
            </if>
            <if test="sgender != null and sgender != ''">
                AND sgender = #{sgender}
            </if>
            <if test="sage != null">
                AND sage = #{sage}
            </if>
        </where>
    </select>

    <!-- 3. 添加学生(主键回填) -->
    <insert id="addStudent" parameterType="Student" useGeneratedKeys="true" keyProperty="sid">
        INSERT INTO student (sname, sgender, sage)
        VALUES (#{sname}, #{sgender}, #{sage})
    </insert>

    <!-- 4. 更新学生(set + if 动态SQL) -->
    <update id="updateStudent" parameterType="Student">
        UPDATE student
        <set>
            <if test="sname != null and sname != ''">
                sname = #{sname},
            </if>
            <if test="sgender != null and sgender != ''">
                sgender = #{sgender},
            </if>
            <if test="sage != null">
                sage = #{sage},
            </if>
        </set>
        WHERE sid = #{sid}
    </update>

    <!-- 5. 删除学生 -->
    <delete id="deleteStudent" parameterType="int">
        DELETE FROM student WHERE sid = #{sid}
    </delete>

    <!-- 6. 根据ID列表查询(foreach) -->
    <select id="selectByIds" resultMap="StudentResultMap">
        SELECT sid, sname, sgender, sage FROM student
        WHERE sid IN
        <foreach collection="ids" item="id" open="(" separator="," close=")">
            #{id}
        </foreach>
    </select>

    <!-- 7. 根据年龄范围查询(@Param) -->
    <select id="selectByAgeRange" resultMap="StudentResultMap">
        SELECT sid, sname, sgender, sage FROM student
        WHERE sage BETWEEN #{minAge} AND #{maxAge}
    </select>

</mapper>

1.3 StudentRepository 接口 原有代码 - 无需修改

说明:此文件由题目完整提供,无需补全。
StudentRepository.java(原有完整代码)
package com.ch.lab.repository;

import com.ch.lab.entity.Student;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;

@Repository
public interface StudentRepository {
    List<Student> findAll();
    List<Student> selectByCondition(Student student);
    int addStudent(Student student);
    int updateStudent(Student student);
    int deleteStudent(int sid);
    List<Student> selectByIds(List<Integer> ids);
    List<Student> selectByAgeRange(@Param("minAge") int minAge, @Param("maxAge") int maxAge);
}

1.4 StudentService 接口 (10分)

说明:原有文件只有 package、import 和 TODO 方法签名。补全部分:7个方法声明。
StudentService.java
package com.ch.lab.service;

import com.ch.lab.entity.Student;
import java.util.List;

public interface StudentService {
    List<Student> findAll();
    List<Student> selectByCondition(Student student);
    int addStudent(Student student);
    int updateStudent(Student student);
    int deleteStudent(int sid);
    List<Student> selectByIds(List<Integer> ids);
    List<Student> selectByAgeRange(int minAge, int maxAge);
}

1.5 StudentServiceImpl 实现类 (10分)

说明:原有文件只有类骨架和 TODO 方法体。补全部分:@Service 注解、@Autowired 注入、7个方法实现(调用 Repository 对应方法)。
StudentServiceImpl.java
package com.ch.lab.service;

import com.ch.lab.entity.Student;
import com.ch.lab.repository.StudentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;

@Service
public class StudentServiceImpl implements StudentService {

    @Autowired
    private StudentRepository studentRepository;

    @Override
    public List<Student> findAll() {
        return studentRepository.findAll();
    }

    @Override
    public List<Student> selectByCondition(Student student) {
        return studentRepository.selectByCondition(student);
    }

    @Override
    public int addStudent(Student student) {
        return studentRepository.addStudent(student);
    }

    @Override
    public int updateStudent(Student student) {
        return studentRepository.updateStudent(student);
    }

    @Override
    public int deleteStudent(int sid) {
        return studentRepository.deleteStudent(sid);
    }

    @Override
    public List<Student> selectByIds(List<Integer> ids) {
        return studentRepository.selectByIds(ids);
    }

    @Override
    public List<Student> selectByAgeRange(int minAge, int maxAge) {
        return studentRepository.selectByAgeRange(minAge, maxAge);
    }
}

1.6 StudentController 控制层 (12分)

说明:原有文件只有类骨架和 TODO 方法体。补全部分:@RestController + @RequestMapping 注解、7个接口方法(含 @GetMapping/@PostMapping/@PutMapping/@DeleteMapping 注解)。
StudentController.java
package com.ch.lab.controller;

import com.ch.lab.entity.Student;
import com.ch.lab.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/students")
public class StudentController {

    @Autowired
    private StudentService studentService;

    // 1. GET /lab_backend/students - 查询所有学生
    @GetMapping
    public List<Student> findAll() {
        return studentService.findAll();
    }

    // 2. GET /lab_backend/students/search?sgender=男 - 条件查询
    @GetMapping("/search")
    public List<Student> selectByCondition(Student student) {
        return studentService.selectByCondition(student);
    }

    // 3. GET /lab_backend/students/age?min=20&max=22 - 年龄范围查询
    @GetMapping("/age")
    public List<Student> selectByAgeRange(@RequestParam("min") int minAge, @RequestParam("max") int maxAge) {
        return studentService.selectByAgeRange(minAge, maxAge);
    }

    // 4. POST /lab_backend/students - 添加学生
    @PostMapping
    public int addStudent(@RequestBody Student student) {
        return studentService.addStudent(student);
    }

    // 5. PUT /lab_backend/students - 更新学生
    @PutMapping
    public int updateStudent(@RequestBody Student student) {
        return studentService.updateStudent(student);
    }

    // 6. DELETE /lab_backend/students/{sid} - 删除学生
    @DeleteMapping("/{sid}")
    public int deleteStudent(@PathVariable("sid") int sid) {
        return studentService.deleteStudent(sid);
    }

    // 7. GET /lab_backend/students/batch?ids=1,3,5 - 批量查询
    @GetMapping("/batch")
    public List<Student> selectByIds(@RequestParam("ids") String idsStr) {
        List<Integer> ids = Arrays.stream(idsStr.split(","))
                .map(Integer::parseInt)
                .collect(Collectors.toList());
        return studentService.selectByIds(ids);
    }
}

1.7 application.properties (8分 中的4分)

说明:原有文件已配置数据源。补全部分:mybatis.type-aliases-package 和 mybatis.mapper-locations 两行。
application.properties
server.servlet.context-path=/lab_backend
spring.datasource.url=jdbc:mysql://localhost:3306/springtest?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

# MyBatis 配置
mybatis.type-aliases-package=com.ch.lab.entity
mybatis.mapper-locations=classpath:mappers/*.xml

1.8 LabBackendApplication 启动类 (8分 中的4分)

说明:原有文件已有 @SpringBootApplication。补全部分:添加 @MapperScan("com.ch.lab.repository") 注解。
LabBackendApplication.java
package com.ch.lab;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("com.ch.lab.repository")
public class LabBackendApplication {
    public static void main(String[] args) {
        SpringApplication.run(LabBackendApplication.class, args);
    }
}

第二大题:Vue 前端开发(8个页面) (40分)

页面1 - 学生信息展示 (5分)

补全部分:Vue.createApp + data + 插值表达式 + app.mount
page1.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>页面1 - 学生信息展示</title>
    <style>
        body { background: #1e1e1e; color: #d4d4d4; font-family: 'Consolas', 'Monaco', monospace; padding: 20px; }
        h1 { color: #569cd6; }
        p { color: #9cdcfe; }
    </style>
</head>
<body>
    <div id="app">
        <h1>学生信息展示</h1>
        <p>姓名:{{ name }}</p>
        <p>学号:{{ studentId }}</p>
        <p>专业:{{ major }}</p>
    </div>
    <script src="js/vue.global.js"></script>
    <script>
        const app = Vue.createApp({
            data() {
                return {
                    name: '张三',
                    studentId: '2024001',
                    major: '计算机科学与技术'
                }
            }
        })
        app.mount('#app')
    </script>
</body>
</html>

页面2 - 成绩计算 (5分)

补全部分:v-model.number 双向绑定3个输入框 + computed 计算属性(averageScore、gradeLevel)
page2.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>页面2 - 成绩计算</title>
    <style>
        body { background: #1e1e1e; color: #d4d4d4; font-family: 'Consolas', 'Monaco', monospace; padding: 20px; }
        h2 { color: #569cd6; }
        p { color: #9cdcfe; }
        input { background: #2d2d2d; color: #d4d4d4; border: 1px solid #555; padding: 4px 8px; font-family: inherit; }
    </style>
</head>
<body>
    <div id="app">
        <h2>成绩计算</h2>
        <p>成绩1:<input v-model.number="score1" placeholder="请输入成绩1"></p>
        <p>成绩2:<input v-model.number="score2" placeholder="请输入成绩2"></p>
        <p>成绩3:<input v-model.number="score3" placeholder="请输入成绩3"></p>
        <p>平均分:{{ averageScore }}</p>
        <p>等级:{{ gradeLevel }}</p>
    </div>
    <script src="js/vue.global.js"></script>
    <script>
        const app = Vue.createApp({
            data() {
                return {
                    score1: 0,
                    score2: 0,
                    score3: 0
                }
            },
            computed: {
                averageScore() {
                    return ((this.score1 + this.score2 + this.score3) / 3).toFixed(2)
                },
                gradeLevel() {
                    const avg = (this.score1 + this.score2 + this.score3) / 3
                    if (avg >= 90) return '优秀'
                    if (avg >= 80) return '良好'
                    if (avg >= 70) return '中等'
                    if (avg >= 60) return '及格'
                    return '不及格'
                }
            }
        })
        app.mount('#app')
    </script>
</body>
</html>

页面3 - 用户信息表单 (5分)

补全部分:v-model 双向绑定4种控件(input、textarea、radio、select)+ 实时预览区域
page3.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>页面3 - 用户信息表单</title>
    <style>
        body { background: #1e1e1e; color: #d4d4d4; font-family: 'Consolas', 'Monaco', monospace; padding: 20px; }
        h2, h3 { color: #569cd6; }
        p { color: #9cdcfe; }
        input, textarea, select { background: #2d2d2d; color: #d4d4d4; border: 1px solid #555; padding: 4px 8px; font-family: inherit; }
        hr { border-color: #444; }
    </style>
</head>
<body>
    <div id="app">
        <h2>用户信息表单</h2>
        <p>用户名:<input v-model="username" placeholder="请输入用户名"></p>
        <p>简介:<textarea v-model="bio" placeholder="请输入简介"></textarea></p>
        <p>性别:
            <input type="radio" v-model="gender" value="男"> 男
            <input type="radio" v-model="gender" value="女"> 女
        </p>
        <p>城市:
            <select v-model="city">
                <option value="">请选择</option>
                <option value="北京">北京</option>
                <option value="上海">上海</option>
                <option value="广州">广州</option>
                <option value="深圳">深圳</option>
            </select>
        </p>
        <hr>
        <h3>实时预览</h3>
        <p>用户名:{{ username }}</p>
        <p>简介:{{ bio }}</p>
        <p>性别:{{ gender }}</p>
        <p>城市:{{ city }}</p>
    </div>
    <script src="js/vue.global.js"></script>
    <script>
        const app = Vue.createApp({
            data() {
                return {
                    username: '',
                    bio: '',
                    gender: '男',
                    city: ''
                }
            }
        })
        app.mount('#app')
    </script>
</body>
</html>

页面4 - 课程列表 (5分)

补全部分:template 模板(course-item 子组件)+ v-for 循环渲染 + props 接收父组件传值 + app.component 注册
page4.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>页面4 - 课程列表</title>
    <style>
        body { background: #1e1e1e; color: #d4d4d4; font-family: 'Consolas', 'Monaco', monospace; padding: 20px; }
        h2 { color: #569cd6; }
        h3 { color: #4ec9b0; }
        p { color: #9cdcfe; }
    </style>
</head>
<body>
    <template id="course-item">
        <div>
            <h3>课程{{ id }}:{{ title }}</h3>
            <p>学分:{{ credit }}</p>
        </div>
    </template>
    <div id="app">
        <h2>课程列表</h2>
        <course-item
            v-for="course in courses"
            :key="course.id"
            :id="course.id"
            :title="course.title"
            :credit="course.credit">
        </course-item>
    </div>
    <script src="js/vue.global.js"></script>
    <script>
        const app = Vue.createApp({
            data() {
                return {
                    courses: [
                        { id: 1, title: 'Web全栈开发', credit: 4 },
                        { id: 2, title: '数据结构', credit: 3 },
                        { id: 3, title: '操作系统', credit: 3 },
                        { id: 4, title: '数据库原理', credit: 3 }
                    ]
                }
            }
        })

        app.component('course-item', {
            template: '#course-item',
            props: ['id', 'title', 'credit']
        })

        app.mount('#app')
    </script>
</body>
</html>

页面5 - 事件与methods (5分)

补全部分:@click 事件绑定 + methods.increment 方法 + count 数据
page5.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>页面5 - 事件与methods</title>
    <style>
        body { background: #1e1e1e; color: #d4d4d4; font-family: 'Consolas', 'Monaco', monospace; padding: 20px; }
        h2 { color: #569cd6; }
        p { color: #9cdcfe; }
        button { background: #0e639c; color: #fff; border: none; padding: 6px 16px; cursor: pointer; font-family: inherit; }
        button:hover { background: #1177bb; }
    </style>
</head>
<body>
    <div id="app">
        <h2>计数器</h2>
        <p>已点击 {{ count }} 次</p>
        <button @click="increment">点击 +1</button>
    </div>
    <script src="js/vue.global.js"></script>
    <script>
        const app = Vue.createApp({
            data() {
                return {
                    count: 0
                }
            },
            methods: {
                increment() {
                    this.count++
                }
            }
        })
        app.mount('#app')
    </script>
</body>
</html>

页面6 - v-if与v-show (5分)

补全部分:v-if/v-else-if/v-else 条件渲染分支 + v-show 切换 + @click 按钮
page6.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>页面6 - v-if与v-show</title>
    <style>
        body { background: #1e1e1e; color: #d4d4d4; font-family: 'Consolas', 'Monaco', monospace; padding: 20px; }
        h2 { color: #569cd6; }
        p { color: #9cdcfe; }
        input { background: #2d2d2d; color: #d4d4d4; border: 1px solid #555; padding: 4px 8px; font-family: inherit; }
        button { background: #0e639c; color: #fff; border: none; padding: 6px 16px; cursor: pointer; font-family: inherit; }
        button:hover { background: #1177bb; }
        hr { border-color: #444; }
    </style>
</head>
<body>
    <div id="app">
        <h2>成绩等级判定</h2>
        <p>请输入成绩:<input v-model.number="score" placeholder="请输入分数"></p>
        <div>
            <p v-if="score >= 90">优秀</p>
            <p v-else-if="score >= 80">良好</p>
            <p v-else-if="score >= 70">中等</p>
            <p v-else-if="score >= 60">及格</p>
            <p v-else>不及格</p>
        </div>
        <hr>
        <h2>v-show 切换</h2>
        <button @click="visible = !visible">切换显示</button>
        <p v-show="visible">这是一段提示文字(v-show控制)</p>
    </div>
    <script src="js/vue.global.js"></script>
    <script>
        const app = Vue.createApp({
            data() {
                return {
                    score: 0,
                    visible: true
                }
            }
        })
        app.mount('#app')
    </script>
</body>
</html>

页面7 - v-for列表渲染 (5分)

补全部分:v-for 循环简单数组(books)和对象数组(authors)+ data 数据定义
page7.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>页面7 - v-for列表渲染</title>
    <style>
        body { background: #1e1e1e; color: #d4d4d4; font-family: 'Consolas', 'Monaco', monospace; padding: 20px; }
        h2 { color: #569cd6; }
        li { color: #9cdcfe; }
        table { border-collapse: collapse; }
        th { background: #264f78; color: #d4d4d4; padding: 6px 12px; }
        td { color: #9cdcfe; padding: 6px 12px; }
        table, th, td { border: 1px solid #555; }
    </style>
</head>
<body>
    <div id="app">
        <h2>书籍列表</h2>
        <ul>
            <li v-for="(book, index) in books" :key="index">{{ index + 1 }}. {{ book }}</li>
        </ul>
        <h2>作者列表</h2>
        <table border="1">
            <tr>
                <th>姓名</th>
                <th>年龄</th>
                <th>国籍</th>
            </tr>
            <tr v-for="author in authors" :key="author.name">
                <td>{{ author.name }}</td>
                <td>{{ author.age }}</td>
                <td>{{ author.country }}</td>
            </tr>
        </table>
    </div>
    <script src="js/vue.global.js"></script>
    <script>
        const app = Vue.createApp({
            data() {
                return {
                    books: ['Vue.js设计与实现', 'JavaScript高级程序设计', 'CSS世界', 'Node.js实战'],
                    authors: [
                        { name: '鲁迅', age: 55, country: '中国' },
                        { name: '莎士比亚', age: 52, country: '英国' },
                        { name: '海明威', age: 61, country: '美国' },
                        { name: '莫泊桑', age: 43, country: '法国' }
                    ]
                }
            }
        })
        app.mount('#app')
    </script>
</body>
</html>

页面8 - 全局组件注册 (5分)

补全部分:template 模板 + app.component 注册(含 props + data)+ 使用3次组件
page8.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>页面8 - 组件注册</title>
    <style>
        body { background: #1e1e1e; color: #d4d4d4; font-family: 'Consolas', 'Monaco', monospace; padding: 20px; }
        h2 { color: #569cd6; }
        p { color: #9cdcfe; }
        button { background: #0e639c; color: #fff; border: none; padding: 6px 16px; cursor: pointer; font-family: inherit; }
        button:hover { background: #1177bb; }
    </style>
</head>
<body>
    <template id="button-counter">
        <div>
            <p>{{ title }}:{{ count }} 次</p>
            <button @click="count++">点击 +1</button>
        </div>
    </template>
    <div id="app">
        <h2>全局组件 - 计数器</h2>
        <button-counter title="计数器A"></button-counter>
        <button-counter title="计数器B"></button-counter>
        <button-counter title="计数器C"></button-counter>
    </div>
    <script src="js/vue.global.js"></script>
    <script>
        const app = Vue.createApp({})

        app.component('button-counter', {
            template: '#button-counter',
            props: ['title'],
            data() {
                return {
                    count: 0
                }
            }
        })

        app.mount('#app')
    </script>
</body>
</html>

提交要求

打包 lab_backend + lab_vue 两个文件夹,命名:学号_姓名_上机.zip

总分:第一大题60分 + 第二大题40分 = 100分