教师考核档案管理软件:从零搭建全栈Web应用实战指南
一、技术选型与项目初始化
我们采用前后端分离架构,前端使用Vue 3 + Element Plus,后端使用Spring Boot + MySQL。这个组合能快速开发出稳定易用的管理系统。
1.1 环境准备
安装Node.js 18.17.0和Java 17:
检查Node.js版本
node -v
检查Java版本
java -version
安装MySQL 8.0并创建数据库:
CREATE DATABASE teacher_assessment;
CREATE USER 'teacher_admin'@'localhost' IDENTIFIED BY 'YourPassword123!';
GRANT ALL PRIVILEGES ON teacher_assessment. TO 'teacher_admin'@'localhost';
1.2 项目结构创建
创建项目根目录并初始化前后端项目:
mkdir teacher-assessment-system
cd teacher-assessment-system
前端项目
vue create frontend --default
cd frontend
npm install element-plus axios
后端项目
cd ..
spring init --name=backend --dependencies=web,mysql,jpa,security backend
二、数据库设计与实现
2.1 核心表结构
在MySQL中执行以下SQL创建表:

CREATE TABLE teachers (
id INT PRIMARY KEY AUTO_INCREMENT,
teacher_number VARCHAR(20) UNIQUE NOT NULL,
name VARCHAR(50) NOT NULL,
department VARCHAR(100),
position VARCHAR(50),
hire_date DATE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE assessment_records (
id INT PRIMARY KEY AUTO_INCREMENT,
teacher_id INT NOT NULL,
assessment_year YEAR NOT NULL,
teaching_score DECIMAL(5,2),
research_score DECIMAL(5,2),
service_score DECIMAL(5,2),
total_score DECIMAL(5,2),
assessment_grade VARCHAR(10),
reviewer VARCHAR(50),
review_date DATE,
remarks TEXT,
FOREIGN KEY (teacher_id) REFERENCES teachers(id) ON DELETE CASCADE,
UNIQUE KEY unique_teacher_year (teacher_id, assessment_year)
);
CREATE TABLE assessment_files (
id INT PRIMARY KEY AUTO_INCREMENT,
record_id INT NOT NULL,
file_name VARCHAR(255) NOT NULL,
file_path VARCHAR(500) NOT NULL,
file_type VARCHAR(50),
upload_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (record_id) REFERENCES assessment_records(id) ON DELETE CASCADE
);
2.2 JPA实体类配置
在backend/src/main/java/com/teacher/entity/目录下创建实体类:
// Teacher.java
@Entity
@Table(name = "teachers")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Teacher {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "teacher_number", unique = true, nullable = false)
private String teacherNumber;
@Column(nullable = false)
private String name;
private String department;
private String position;
@Column(name = "hire_date")
private Date hireDate;
@Column(name = "created_at")
private Timestamp createdAt;
@PrePersist
protected void onCreate() {
createdAt = new Timestamp(System.currentTimeMillis());
}
}
// AssessmentRecord.java
@Entity
@Table(name = "assessment_records")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class AssessmentRecord {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@ManyToOne
@JoinColumn(name = "teacher_id", nullable = false)
private Teacher teacher;
@Column(name = "assessment_year", nullable = false)
private Integer assessmentYear;
@Column(name = "teaching_score", precision = 5, scale = 2)
private BigDecimal teachingScore;
@Column(name = "research_score", precision = 5, scale = 2)
private BigDecimal researchScore;
@Column(name = "service_score", precision = 5, scale = 2)
private BigDecimal serviceScore;
@Column(name = "total_score", precision = 5, scale = 2)
private BigDecimal totalScore;
@Column(name = "assessment_grade", length = 10)
private String assessmentGrade;
private String reviewer;
@Column(name = "review_date")
private Date reviewDate;
private String remarks;
@PreUpdate
@PrePersist
public void calculateTotalScore() {
if (teachingScore != null && researchScore != null && serviceScore != null) {
totalScore = teachingScore.add(researchScore).add(serviceScore);
}
}
}
三、后端API开发
3.1 配置文件
配置application.properties:
数据库配置
spring.datasource.url=jdbc:mysql://localhost:3306/teacher_assessment?useSSL=false&serverTimezone=UTC&characterEncoding=UTF-8
spring.datasource.username=teacher_admin
spring.datasource.password=YourPassword123!
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
JPA配置
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
spring.jpa.properties.hibernate.format_sql=true
文件上传配置
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=10MB
跨域配置(开发环境)
cors.allowed-origins=http://localhost:8080
3.2 控制器实现
创建TeacherController.java:
@RestController
@RequestMapping("/api/teachers")
@CrossOrigin(origins = "${cors.allowed-origins}")
public class TeacherController {
@Autowired
private TeacherRepository teacherRepository;
@GetMapping
public ResponseEntity> getAllTeachers() {
return ResponseEntity.ok(teacherRepository.findAll());
}
@GetMapping("/{id}")
public ResponseEntity getTeacherById(@PathVariable Integer id) {
return teacherRepository.findById(id)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
@PostMapping
public ResponseEntity createTeacher(@Valid @RequestBody Teacher teacher) {
Teacher savedTeacher = teacherRepository.save(teacher);
return ResponseEntity.status(HttpStatus.CREATED).body(savedTeacher);
}
@PutMapping("/{id}")
public ResponseEntity updateTeacher(@PathVariable Integer id,
@Valid @RequestBody Teacher teacherDetails) {
return teacherRepository.findById(id)
.map(teacher -> {
teacher.setName(teacherDetails.getName());
teacher.setDepartment(teacherDetails.getDepartment());
teacher.setPosition(teacherDetails.getPosition());
teacher.setHireDate(teacherDetails.getHireDate());
Teacher updatedTeacher = teacherRepository.save(teacher);
return ResponseEntity.ok(updatedTeacher);
})
.orElse(ResponseEntity.notFound().build());
}
@GetMapping("/search")
public ResponseEntity> searchTeachers(
@RequestParam(required = false) String name,
@RequestParam(required = false) String department) {
Specification spec = Specification.where(null);
if (name != null && !name.isEmpty()) {
spec = spec.and((root, query, cb) ->
cb.like(root.get("name"), "%" + name + "%"));
}
if (department != null && !department.isEmpty()) {
spec = spec.and((root, query, cb) ->
cb.equal(root.get("department"), department));
}
return ResponseEntity.ok(teacherRepository.findAll(spec));
}
}
3.3 文件上传接口
创建FileController.java处理考核文件上传:
@RestController
@RequestMapping("/api/files")
public class FileController {
@Value("${file.upload-dir}")
private String uploadDir;
@PostMapping("/upload")
public ResponseEntity
四、前端界面开发
4.1 项目配置
配置vue.config.js:
module.exports = {
devServer: {
port: 8080,
proxy: {
'/api': {
target: 'http://localhost:8081',
changeOrigin: true
}
}
}
}
4.2 教师管理组件
创建TeacherList.vue:
教师信息管理
新增教师
搜索
重置
{{ formatDate(scope.row.hireDate) }}
编辑
考核记录
删除