招生就业管理系统是高校信息化建设中的重要一环,它直接关系到学校招生宣传、学生信息管理、就业服务等核心业务流程的数字化水平。传统的手工操作或单机版管理系统已经无法满足现代高校对数据实时性、流程协同性和移动办公的需求。
这个基于SpringBoot和Vue的全栈系统,采用了前后端分离的架构设计。后端使用SpringBoot提供RESTful API接口,前端使用Vue.js构建响应式用户界面,两者通过HTTP协议进行数据交互。这种架构既保证了系统的可维护性和扩展性,又能提供良好的用户体验。
提示:选择SpringBoot+Vue的技术栈,主要考虑到Java生态在企业级应用中的成熟度,以及Vue在构建现代化前端界面时的灵活性。这两个框架都有丰富的社区支持和文档资源,非常适合高校信息化系统的开发。
后端技术栈:
前端技术栈:
系统主要分为以下几个功能模块:
用户管理模块
招生管理模块
就业管理模块
系统管理模块
用户相关表:
sql复制CREATE TABLE `sys_user` (
`user_id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户ID',
`username` varchar(50) NOT NULL COMMENT '用户名',
`password` varchar(100) NOT NULL COMMENT '密码',
`real_name` varchar(50) DEFAULT NULL COMMENT '真实姓名',
`phone` varchar(20) DEFAULT NULL COMMENT '手机号',
`email` varchar(100) DEFAULT NULL COMMENT '邮箱',
`avatar` varchar(255) DEFAULT NULL COMMENT '头像',
`status` tinyint DEFAULT '1' COMMENT '状态(0停用 1正常)',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`user_id`),
UNIQUE KEY `idx_username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
招生相关表:
sql复制CREATE TABLE `recruit_student` (
`id` bigint NOT NULL AUTO_INCREMENT,
`exam_number` varchar(50) NOT NULL COMMENT '准考证号',
`name` varchar(50) NOT NULL COMMENT '姓名',
`gender` tinyint DEFAULT NULL COMMENT '性别',
`id_card` varchar(18) NOT NULL COMMENT '身份证号',
`phone` varchar(20) DEFAULT NULL COMMENT '联系电话',
`address` varchar(255) DEFAULT NULL COMMENT '通讯地址',
`major_id` bigint DEFAULT NULL COMMENT '报考专业',
`score` decimal(10,2) DEFAULT NULL COMMENT '考试成绩',
`admission_status` tinyint DEFAULT '0' COMMENT '录取状态',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_exam_number` (`exam_number`),
UNIQUE KEY `idx_id_card` (`id_card`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='考生信息表';
系统采用符合第三范式的关系型数据库设计,主要实体关系包括:
注意:对于高频查询的表(如招生计划、招聘信息),我们添加了适当的冗余字段以减少联表查询,在数据一致性和查询性能之间取得平衡。
主启动类配置:
java复制@SpringBootApplication
@MapperScan("com.admission.system.mapper")
@EnableScheduling
@EnableAsync
public class AdmissionSystemApplication {
public static void main(String[] args) {
SpringApplication.run(AdmissionSystemApplication.class, args);
}
}
安全配置类:
java复制@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/auth/login").anonymous()
.antMatchers("/swagger-ui/**").permitAll()
.antMatchers("/webjars/**").permitAll()
.antMatchers("/swagger-resources/**").permitAll()
.antMatchers("/v2/api-docs").permitAll()
.anyRequest().authenticated();
http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
}
}
招生计划服务实现:
java复制@Service
public class RecruitPlanServiceImpl implements RecruitPlanService {
@Autowired
private RecruitPlanMapper recruitPlanMapper;
@Override
@Transactional
public void addPlan(RecruitPlanDTO planDTO) {
// 校验招生计划是否冲突
LambdaQueryWrapper<RecruitPlan> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(RecruitPlan::getYear, planDTO.getYear())
.eq(RecruitPlan::getMajorId, planDTO.getMajorId());
if(recruitPlanMapper.selectCount(queryWrapper) > 0) {
throw new BusinessException("该专业本年度招生计划已存在");
}
// DTO转Entity
RecruitPlan plan = new RecruitPlan();
BeanUtils.copyProperties(planDTO, plan);
plan.setCreateTime(LocalDateTime.now());
if(recruitPlanMapper.insert(plan) <= 0) {
throw new BusinessException("添加招生计划失败");
}
}
@Override
public PageResult<RecruitPlanVO> queryPlanList(PlanQueryDTO queryDTO) {
Page<RecruitPlan> page = new Page<>(queryDTO.getPageNum(), queryDTO.getPageSize());
LambdaQueryWrapper<RecruitPlan> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(queryDTO.getYear() != null, RecruitPlan::getYear, queryDTO.getYear())
.eq(queryDTO.getMajorId() != null, RecruitPlan::getMajorId, queryDTO.getMajorId())
.orderByDesc(RecruitPlan::getCreateTime);
Page<RecruitPlan> planPage = recruitPlanMapper.selectPage(page, queryWrapper);
// 转换VO
List<RecruitPlanVO> voList = planPage.getRecords().stream().map(plan -> {
RecruitPlanVO vo = new RecruitPlanVO();
BeanUtils.copyProperties(plan, vo);
// 补充专业名称等信息
vo.setMajorName(majorService.getMajorNameById(plan.getMajorId()));
return vo;
}).collect(Collectors.toList());
return new PageResult<>(voList, planPage.getTotal());
}
}
code复制src/
├── api/ # API请求封装
├── assets/ # 静态资源
├── components/ # 公共组件
├── composables/ # 组合式函数
├── router/ # 路由配置
├── stores/ # Pinia状态管理
├── styles/ # 全局样式
├── utils/ # 工具函数
├── views/ # 页面组件
│ ├── admission/ # 招生管理
│ ├── employment/ # 就业管理
│ ├── system/ # 系统管理
│ └── ...
└── main.js # 应用入口
招生计划管理页面:
vue复制<template>
<div class="plan-container">
<el-card shadow="never">
<template #header>
<div class="card-header">
<span>招生计划管理</span>
<el-button type="primary" @click="handleAdd">新增计划</el-button>
</div>
</template>
<el-form :model="queryParams" inline>
<el-form-item label="年份">
<el-date-picker
v-model="queryParams.year"
type="year"
placeholder="选择年份"
value-format="yyyy"
/>
</el-form-item>
<el-form-item label="专业">
<el-select v-model="queryParams.majorId" clearable>
<el-option
v-for="item in majorOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleQuery">查询</el-button>
<el-button @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-table
:data="planList"
v-loading="loading"
border
style="width: 100%"
>
<el-table-column prop="year" label="年份" width="100" />
<el-table-column prop="majorName" label="专业" />
<el-table-column prop="planNumber" label="计划人数" width="120" />
<el-table-column prop="actualNumber" label="已录取" width="120" />
<el-table-column prop="createTime" label="创建时间" width="180" />
<el-table-column label="操作" width="180" fixed="right">
<template #default="scope">
<el-button size="small" @click="handleEdit(scope.row)">编辑</el-button>
<el-button size="small" type="danger" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</el-card>
<!-- 新增/编辑对话框 -->
<plan-dialog
v-model="dialogVisible"
:mode="dialogMode"
:current-row="currentRow"
@success="handleSuccess"
/>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { getPlanList, deletePlan } from '@/api/admission'
import { getMajorOptions } from '@/api/system'
import PlanDialog from './components/PlanDialog.vue'
const queryParams = ref({
pageNum: 1,
pageSize: 10,
year: null,
majorId: null
})
const planList = ref([])
const total = ref(0)
const loading = ref(false)
const majorOptions = ref([])
// 获取招生计划列表
const getList = async () => {
try {
loading.value = true
const res = await getPlanList(queryParams.value)
planList.value = res.rows
total.value = res.total
} finally {
loading.value = false
}
}
// 获取专业选项
const getMajors = async () => {
const res = await getMajorOptions()
majorOptions.value = res.data
}
onMounted(() => {
getList()
getMajors()
})
</script>
后端环境:
前端环境:
方案一:传统服务器部署
bash复制mvn clean package -DskipTests
bash复制npm run build
nginx复制server {
listen 80;
server_name yourdomain.com;
location / {
root /path/to/dist;
try_files $uri $uri/ /index.html;
}
location /api/ {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
方案二:Docker容器化部署
dockerfile复制# 后端Dockerfile
FROM openjdk:11-jre
COPY target/admission-system.jar /app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
# 前端Dockerfile
FROM nginx:alpine
COPY dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
yaml复制version: '3'
services:
backend:
build: ./backend
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=prod
depends_on:
- mysql
- redis
frontend:
build: ./frontend
ports:
- "80:80"
mysql:
image: mysql:8.0
environment:
- MYSQL_ROOT_PASSWORD=yourpassword
- MYSQL_DATABASE=admission_db
volumes:
- mysql_data:/var/lib/mysql
redis:
image: redis:6-alpine
ports:
- "6379:6379"
volumes:
mysql_data:
多维度数据统计
灵活的权限控制
高性能设计
移动端适配
系统安全
前端跨域问题
javascript复制devServer: {
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true
}
}
}
大文件上传失败
yaml复制spring:
servlet:
multipart:
max-file-size: 50MB
max-request-size: 50MB
并发录取数据不一致
java复制@Update("update recruit_plan set actual_number = actual_number + 1, version = version + 1 where id = #{id} and version = #{version}")
int updateWithVersion(@Param("id") Long id, @Param("version") Integer version);
定时任务执行缓慢
java复制@Async
@Scheduled(cron = "0 0 2 * * ?")
public void generateDailyReport() {
// 报表生成逻辑
}
前端页面加载慢
javascript复制const Admission = () => import('@/views/admission/index.vue')
微信小程序集成
智能分析模块
第三方系统对接
微服务改造
国际化支持
前后端协作
代码规范
性能优化
测试建议
部署建议
这个招生就业管理系统从设计到实现,涵盖了高校招生就业管理的主要业务流程。采用SpringBoot和Vue技术栈,既保证了系统的稳定性和性能,又能提供良好的用户体验。在实际开发过程中,特别需要注意业务流程的合理性和数据的安全性。系统还有很多可以扩展和优化的空间,开发者可以根据实际需求进行二次开发。