ITPub博客

首页 > 应用开发 > IT综合 > 高校成绩管理系统开发实践:SpringBoot技术实现方案

高校成绩管理系统开发实践:SpringBoot技术实现方案

IT综合 作者:bhluo 时间:2025-11-13 16:02:51 0 删除 编辑

### 高校成绩管理系统开发实践:SpringBoot技术实现方案


在高校信息化建设进程中,成绩管理系统作为教学管理的核心环节,对提升教务工作效率具有重要意义。基于SpringBoot框架的成绩管理系统能够有效整合学生信息、课程数据和成绩记录,为教学管理提供数字化支持。


#### 系统架构设计与技术选型


**整体技术架构**

采用分层架构设计,确保系统可维护性和扩展性:

- 前端展示层:Thymeleaf模板引擎 + Bootstrap

- 业务逻辑层:Spring Boot + Spring MVC

- 数据持久层:Spring Data JPA + MySQL

- 安全控制层:Spring Security


**项目依赖配置**

Maven核心依赖配置:


```xml

<dependencies>

    <dependency>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-starter-web</artifactId>

    </dependency>

    <dependency>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-starter-data-jpa</artifactId>

    </dependency>

    <dependency>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-starter-thymeleaf</artifactId>

    </dependency>

    <dependency>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-starter-security</artifactId>

    </dependency>

    <dependency>

        <groupId>mysql</groupId>

        <artifactId>mysql-connector-java</artifactId>

        <scope>runtime</scope>

    </dependency>

<"LFP.Bundesliga.wqbty.cn">

<"LaLiga.Bundesliga.wqbty.cn">

<"www.LFP.wqbty.cn">

</dependencies>

```


#### 数据库设计与实体建模


**核心数据表结构**

设计符合第三范式的数据库结构:


```sql

-- 学生信息表

CREATE TABLE students (

    id BIGINT AUTO_INCREMENT PRIMARY KEY,

    student_number VARCHAR(20) UNIQUE NOT NULL,

    name VARCHAR(50) NOT NULL,

    gender ENUM('MALE', 'FEMALE'),

    enrollment_date DATE,

    major VARCHAR(100),

    class_name VARCHAR(50),

    created_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP

);


-- 课程信息表

CREATE TABLE courses (

    id BIGINT AUTO_INCREMENT PRIMARY KEY,

    course_code VARCHAR(20) UNIQUE NOT NULL,

    course_name VARCHAR(100) NOT NULL,

    credit DECIMAL(3,1) NOT NULL,

    course_hours INT,

    teacher_name VARCHAR(50),

    semester VARCHAR(20)

);

<"wap.LFP.wqbty.cn">

<"m.LFP.wqbty.cn">

<"share.LFP.wqbty.cn">


-- 成绩记录表

CREATE TABLE scores (

    id BIGINT AUTO_INCREMENT PRIMARY KEY,

    student_id BIGINT NOT NULL,

    course_id BIGINT NOT NULL,

    regular_score DECIMAL(5,2),

    final_score DECIMAL(5,2),

    total_score DECIMAL(5,2),

    grade_point DECIMAL(3,2),

    academic_year VARCHAR(20),

    semester VARCHAR(10),

    created_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

    FOREIGN KEY (student_id) REFERENCES students(id),

    FOREIGN KEY (course_id) REFERENCES courses(id),

    UNIQUE KEY uk_student_course (student_id, course_id)

);

```


**JPA实体类设计**

实现对象关系映射:


```java

@Entity

@Table(name = "students")

@Data

public class Student {

    @Id

    @GeneratedValue(strategy = GenerationType.IDENTITY)

    private Long id;

    

    @Column(name = "student_number", unique = true, nullable = false, length = 20)

    private String studentNumber;

    

    @Column(nullable = false, length = 50)

    private String name;

    

    @Enumerated(EnumType.STRING)

    private Gender gender;

    

    @Column(name = "enrollment_date")

    private LocalDate enrollmentDate;

    

    @Column(length = 100)

    private String major;

    

    @Column(name = "class_name", length = 50)

    private String className;

    

    @CreationTimestamp

    @Column(name = "created_time")

    private LocalDateTime createdTime;

    

    @OneToMany(mappedBy = "student", cascade = CascadeType.ALL)

    private List<Score> scores = new ArrayList<>();

}

<"ei.LFP.wqbty.cn">

<"movie.LFP.wqbty.cn">

<"live.LFP.wqbty.cn">


@Entity

@Table(name = "courses")

@Data

public class Course {

    @Id

    @GeneratedValue(strategy = GenerationType.IDENTITY)

    private Long id;

    

    @Column(name = "course_code", unique = true, nullable = false, length = 20)

    private String courseCode;

    

    @Column(name = "course_name", nullable = false, length = 100)

    private String courseName;

    

    @Column(nullable = false, precision = 3, scale = 1)

    private BigDecimal credit;

    

    @Column(name = "course_hours")

    private Integer courseHours;

    

    @Column(name = "teacher_name", length = 50)

    private String teacherName;

    

    private String semester;

}


@Entity

@Table(name = "scores", 

       uniqueConstraints = @UniqueConstraint(columnNames = {"student_id", "course_id"}))

@Data

public class Score {

    @Id

    @GeneratedValue(strategy = GenerationType.IDENTITY)

    private Long id;

<"sport.LFP.wqbty.cn">

<"football.LFP.wqbty.cn">

<"basketball.LFP.wqbty.cn">

    

    @ManyToOne(fetch = FetchType.LAZY)

    @JoinColumn(name = "student_id", nullable = false)

    private Student student;

    

    @ManyToOne(fetch = FetchType.LAZY)

    @JoinColumn(name = "course_id", nullable = false)

    private Course course;

    

    @Column(name = "regular_score", precision = 5, scale = 2)

    private BigDecimal regularScore;

    

    @Column(name = "final_score", precision = 5, scale = 2)

    private BigDecimal finalScore;

    

    @Column(name = "total_score", precision = 5, scale = 2)

    private BigDecimal totalScore;

    

    @Column(name = "grade_point", precision = 3, scale = 2)

    private BigDecimal gradePoint;

    

    @Column(name = "academic_year", length = 20)

    private String academicYear;

    

    private String semester;

    

    @CreationTimestamp

    @Column(name = "created_time")

    private LocalDateTime createdTime;

    

    @PrePersist

    @PreUpdate

    public void calculateScores() {

        // 计算总评成绩和绩点

        if (regularScore != null && finalScore != null) {

            this.totalScore = regularScore.multiply(BigDecimal.valueOf(0.3))

                .add(finalScore.multiply(BigDecimal.valueOf(0.7)));

            this.gradePoint = calculateGradePoint(totalScore);

        }

    }

    

    private BigDecimal calculateGradePoint(BigDecimal score) {

        if (score.compareTo(BigDecimal.valueOf(90)) >= 0) {

            return BigDecimal.valueOf(4.0);

        } else if (score.compareTo(BigDecimal.valueOf(80)) >= 0) {

            return BigDecimal.valueOf(3.0);

        } else if (score.compareTo(BigDecimal.valueOf(70)) >= 0) {

            return BigDecimal.valueOf(2.0);

        } else if (score.compareTo(BigDecimal.valueOf(60)) >= 0) {

            return BigDecimal.valueOf(1.0);

        } else {

<"tv.LFP.wqbty.cn">

<"trending.LFP.wqbty.cn">

<"crawler.LFP.wqbty.cn">

            return BigDecimal.ZERO;

        }

    }

}

```


#### 业务逻辑层实现


**服务层接口设计**

定义成绩管理核心业务接口:


```java

public interface ScoreService {

    

    Page<ScoreDTO> getScoresByStudent(String studentNumber, int page, int size);

    

    Page<ScoreDTO> getScoresByCourse(String courseCode, int page, int size);

    

    ScoreDTO recordScore(ScoreRecordDTO recordDTO);

    

    void updateScore(Long scoreId, ScoreUpdateDTO updateDTO);

    

    void deleteScore(Long scoreId);

    

    StudentGPA calculateGPA(String studentNumber);

    

    Map<String, Object> getCourseStatistics(String courseCode);

}


@Service

@Transactional

public class ScoreServiceImpl implements ScoreService {

    

    @Autowired

    private ScoreRepository scoreRepository;

    

    @Autowired

    private StudentRepository studentRepository;

    

    @Autowired

    private CourseRepository courseRepository;

    

    @Override

    public Page<ScoreDTO> getScoresByStudent(String studentNumber, int page, int size) {

        Pageable pageable = PageRequest.of(page, size, Sort.by("semester").descending());

        return scoreRepository.findByStudentStudentNumber(studentNumber, pageable)

                .map(this::convertToDTO);

    }

<"gold.LFP.wqbty.cn">

<"EPL.LFP.wqbty.cn">

<"CFL.LFP.wqbty.cn">

    

    @Override

    public ScoreDTO recordScore(ScoreRecordDTO recordDTO) {

        Student student = studentRepository.findByStudentNumber(recordDTO.getStudentNumber())

                .orElseThrow(() -> new ResourceNotFoundException("学生不存在"));

        

        Course course = courseRepository.findByCourseCode(recordDTO.getCourseCode())

                .orElseThrow(() -> new ResourceNotFoundException("课程不存在"));

        

        // 检查是否已存在成绩记录

        if (scoreRepository.existsByStudentAndCourse(student, course)) {

            throw new BusinessException("该学生在此课程中已有成绩记录");

        }

        

        Score score = new Score();

        score.setStudent(student);

        score.setCourse(course);

        score.setRegularScore(recordDTO.getRegularScore());

        score.setFinalScore(recordDTO.getFinalScore());

        score.setAcademicYear(recordDTO.getAcademicYear());

        score.setSemester(recordDTO.getSemester());

        

        Score savedScore = scoreRepository.save(score);

        return convertToDTO(savedScore);

    }

    

    @Override

    public StudentGPA calculateGPA(String studentNumber) {

        List<Score> scores = scoreRepository.findByStudentStudentNumber(studentNumber);

        

        BigDecimal totalCredits = BigDecimal.ZERO;

        BigDecimal totalGradePoints = BigDecimal.ZERO;

        

        for (Score score : scores) {

            if (score.getGradePoint() != null && score.getCourse().getCredit() != null) {

                BigDecimal credit = score.getCourse().getCredit();

                BigDecimal gradePoint = score.getGradePoint();

                

                totalCredits = totalCredits.add(credit);

                totalGradePoints = totalGradePoints.add(credit.multiply(gradePoint));

            }

        }

        

        BigDecimal gpa = totalCredits.compareTo(BigDecimal.ZERO) > 0 ?

                totalGradePoints.divide(totalCredits, 2, RoundingMode.HALF_UP) :

                BigDecimal.ZERO;

        

        return new StudentGPA(studentNumber, gpa, totalCredits);

    }

    

    private ScoreDTO convertToDTO(Score score) {

        return ScoreDTO.builder()

                .id(score.getId())

                .studentNumber(score.getStudent().getStudentNumber())

                .studentName(score.getStudent().getName())

                .courseCode(score.getCourse().getCourseCode())

                .courseName(score.getCourse().getCourseName())

                .credit(score.getCourse().getCredit())

                .regularScore(score.getRegularScore())

                .finalScore(score.getFinalScore())

                .totalScore(score.getTotalScore())

                .gradePoint(score.getGradePoint())

                .academicYear(score.getAcademicYear())

                .semester(score.getSemester())

                .build();

<"SerieA.LFP.wqbty.cn">

<"www.UEFA.zqbty.cn">

<"wap.UEFA.zqbty.cn">

    }

}

```


#### 控制层与API设计


**RESTful API接口**

提供前后端分离的API接口:


```java

@RestController

@RequestMapping("/api/scores")

@Validated

public class ScoreController {

    

    @Autowired

    private ScoreService scoreService;

    

    @GetMapping("/student/{studentNumber}")

    public ResponseEntity<PageResult<ScoreDTO>> getStudentScores(

            @PathVariable String studentNumber,

            @RequestParam(defaultValue = "0") int page,

            @RequestParam(defaultValue = "10") int size) {

        

        Page<ScoreDTO> scorePage = scoreService.getScoresByStudent(studentNumber, page, size);

        PageResult<ScoreDTO> result = PageResult.from(scorePage);

        return ResponseEntity.ok(result);

    }

    

    @PostMapping

    public ResponseEntity<ScoreDTO> recordScore(

            @Valid @RequestBody ScoreRecordDTO recordDTO) {

        

        ScoreDTO scoreDTO = scoreService.recordScore(recordDTO);

        return ResponseEntity.status(HttpStatus.CREATED).body(scoreDTO);

    }

    

    @PutMapping("/{id}")

    public ResponseEntity<ScoreDTO> updateScore(

            @PathVariable Long id,

            @Valid @RequestBody ScoreUpdateDTO updateDTO) {

        

        scoreService.updateScore(id, updateDTO);

        return ResponseEntity.ok().build();

    }

<"m.UEFA.zqbty.cn">

<"share.UEFA.zqbty.cn">

<"ei.UEFA.zqbty.cn">

    

    @GetMapping("/student/{studentNumber}/gpa")

    public ResponseEntity<StudentGPA> calculateGPA(@PathVariable String studentNumber) {

        StudentGPA gpa = scoreService.calculateGPA(studentNumber);

        return ResponseEntity.ok(gpa);

    }

}


// 数据传输对象定义

@Data

@Builder

public class ScoreDTO {

    private Long id;

    private String studentNumber;

    private String studentName;

    private String courseCode;

    private String courseName;

    private BigDecimal credit;

    private BigDecimal regularScore;

    private BigDecimal finalScore;

    private BigDecimal totalScore;

    private BigDecimal gradePoint;

    private String academicYear;

    private String semester;

}


@Data

public class ScoreRecordDTO {

    @NotBlank(message = "学号不能为空")

    private String studentNumber;

    

    @NotBlank(message = "课程代码不能为空")

    private String courseCode;

    

    @DecimalMin(value = "0.0", message = "平时成绩不能小于0")

    @DecimalMax(value = "100.0", message = "平时成绩不能大于100")

    private BigDecimal regularScore;

    

    @DecimalMin(value = "0.0", message = "期末成绩不能小于0")

    @DecimalMax(value = "100.0", message = "期末成绩不能大于100")

    private BigDecimal finalScore;

    

    @NotBlank(message = "学年不能为空")

    private String academicYear;

    

    @NotBlank(message = "学期不能为空")

    private String semester;

}

```


#### 前端界面与交互实现


**Thymeleaf模板页面**

实现成绩查询和管理的界面:


```html

<!DOCTYPE html>

<html xmlns:th="http://www.thymeleaf.org">

<head>

<"movie.UEFA.zqbty.cn">

<"live.UEFA.zqbty.cn">

<"sport.UEFA.zqbty.cn">

    <meta charset="UTF-8">

    <title>成绩管理系统</title>

    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">

</head>

<body>

    <div class="container mt-4">

        <h2>学生成绩查询</h2>

        

        <form th:action="@{/scores/search}" method="get" class="row g-3 mb-4">

            <div class="col-md-4">

                <input type="text" name="studentNumber" class="form-control" 

                       placeholder="输入学号" th:value="${studentNumber}">

            </div>

            <div class="col-md-4">

                <input type="text" name="courseCode" class="form-control" 

                       placeholder="输入课程代码" th:value="${courseCode}">

            </div>

            <div class="col-md-4">

                <button type="submit" class="btn btn-primary">查询</button>

            </div>

        </form>

        

        <div th:if="${scores != null && !scores.empty}">

            <table class="table table-striped">

                <thead>

                    <tr>

                        <th>学号</th>

                        <th>姓名</th>

                        <th>课程代码</th>

                        <th>课程名称</th>

                        <th>平时成绩</th>

                        <th>期末成绩</th>

                        <th>总评成绩</th>

                        <th>绩点</th>

                        <th>学期</th>

                    </tr>

                </thead>

                <tbody>

                    <tr th:each="score : ${scores}">

                        <td th:text="${score.studentNumber}"></td>

                        <td th:text="${score.studentName}"></td>

                        <td th:text="${score.courseCode}"></td>

                        <td th:text="${score.courseName}"></td>

                        <td th:text="${score.regularScore}"></td>

                        <td th:text="${score.finalScore}"></td>

                        <td th:text="${score.totalScore}"></td>

                        <td th:text="${score.gradePoint}"></td>

                        <td th:text="${score.semester}"></td>

                    </tr>

                </tbody>

            </table>

        </div>

        

        <div th:if="${scores != null && scores.empty}" class="alert alert-info">

            未找到相关成绩记录

        </div>

    </div>

</body>

</html>

```


#### 系统安全与权限控制


**Spring Security配置**

实现基于角色的访问控制:


```java

@Configuration

@EnableWebSecurity

public class SecurityConfig {

    

    @Bean

    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

        http

            .authorizeHttpRequests(authz -> authz

                .requestMatchers("/css/**", "/js/**", "/login").permitAll()

                .requestMatchers("/admin/**").hasRole("ADMIN")

                .requestMatchers("/teacher/**").hasAnyRole("TEACHER", "ADMIN")

                .requestMatchers("/student/**").hasAnyRole("STUDENT", "TEACHER", "ADMIN")

                .anyRequest().authenticated()

            )

<"football.UEFA.zqbty.cn">

<"basketball.UEFA.zqbty.cn">

<"tv.UEFA.zqbty.cn">

            .formLogin(form -> form

                .loginPage("/login")

                .defaultSuccessUrl("/dashboard")

                .permitAll()

            )

            .logout(logout -> logout

                .logoutSuccessUrl("/login?logout")

                .permitAll()

            );

        

        return http.build();

    }

}

```


#### 系统测试与验证


**单元测试用例**

确保业务逻辑的正确性:


```java

@SpringBootTest

class ScoreServiceTest {

    

    @Autowired

    private ScoreService scoreService;

    

    @Test

    void testRecordScore_Success() {

        ScoreRecordDTO recordDTO = new ScoreRecordDTO();

        recordDTO.setStudentNumber("2023001001");

        recordDTO.setCourseCode("CS001");

        recordDTO.setRegularScore(BigDecimal.valueOf(85.0));

        recordDTO.setFinalScore(BigDecimal.valueOf(90.0));

        recordDTO.setAcademicYear("2023-2024");

        recordDTO.setSemester("第一学期");

        

        ScoreDTO result = scoreService.recordScore(recordDTO);

        

        assertNotNull(result.getId());

        assertEquals(BigDecimal.valueOf(88.5), result.getTotalScore());

        assertEquals(BigDecimal.valueOf(3.0), result.getGradePoint());

    }

}

```


基于SpringBoot的大学生成绩管理系统通过模块化设计和分层架构,实现了学生信息管理、课程管理和成绩管理等核心功能。系统采用RESTful API设计,支持前后端分离开发,具有良好的扩展性和维护性。通过合理的数据库设计和业务逻辑实现,为高校教务管理提供了可靠的数字化解决方案。


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/19545/viewspace-3101348/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2015-11-01

  • 博文量
    895
  • 访问量
    933611