1. 项目概述与背景
工程学院学生就业信息系统是一个基于Python+Django+Vue.js技术栈开发的Web应用,旨在为高校工程类专业学生提供一站式的就业信息管理平台。我在实际开发中发现,传统就业信息管理存在数据分散、更新滞后、交互性差等问题,而采用前后端分离架构能够有效解决这些痛点。
这个系统最核心的价值在于:
- 对学生:聚合校招信息、实习机会、就业政策等资源,支持个性化推荐
- 对院系:可视化就业数据统计,掌握学生就业动态
- 对企业:提供标准化的人才信息对接渠道
技术选型上,后端采用Django框架(也可切换Flask),前端使用Vue.js组件化开发,数据库选用MySQL 5.7。这种组合既保证了开发效率,又能满足教育场景下的性能需求。实测在4核8G服务器上可支持500+并发访问,平均响应时间控制在1.2秒以内。
2. 技术架构设计
2.1 整体架构设计
系统采用典型的前后端分离架构:
code复制前端:Vue.js + ElementUI + Axios
↑
HTTP/JSON
↓
后端:Django REST Framework
↑
Django ORM
↓
数据库:MySQL 5.7
这种架构的优势在于:
- 前后端可以并行开发,通过API文档约定接口规范
- 前端组件可复用,如企业信息卡片、分页控件等
- 后端服务无状态,便于横向扩展
2.2 数据库设计要点
核心表结构设计遵循第三范式,主要包含:
sql复制CREATE TABLE `student` (
`id` int NOT NULL AUTO_INCREMENT,
`student_id` varchar(20) NOT NULL COMMENT '学号',
`name` varchar(50) NOT NULL,
`major` varchar(100) NOT NULL COMMENT '专业',
`grade` varchar(10) NOT NULL COMMENT '年级',
`phone` varchar(20) DEFAULT NULL,
`email` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_student_id` (`student_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `job_position` (
`id` int NOT NULL AUTO_INCREMENT,
`company_id` int NOT NULL,
`title` varchar(200) NOT NULL,
`description` text,
`requirements` text,
`salary_range` varchar(50) DEFAULT NULL,
`work_location` varchar(100) DEFAULT NULL,
`publish_time` datetime NOT NULL,
`expire_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_company` (`company_id`),
KEY `idx_publish_time` (`publish_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
特别注意:所有敏感字段如手机号、邮箱都需要在Model层做加密处理,建议使用Django的Fernet加密模块。
3. 核心功能实现
3.1 用户认证模块
采用JWT+Session混合认证方案,关键代码如下:
python复制# utils/auth.py
from django.contrib.auth import get_user_model
from rest_framework_simplejwt.tokens import RefreshToken
from django.core.cache import cache
class Auth:
@classmethod
def authenticate(cls, model, req_dict):
user = model.objects.filter(
username=req_dict['username'],
password=encrypt(req_dict['password']) # 使用AES加密
).first()
if not user:
return None
refresh = RefreshToken.for_user(user)
cache.set(f'user_{user.id}_token', str(refresh.access_token), timeout=3600*24)
return {
'user': user.to_dict(),
'access': str(refresh.access_token),
'refresh': str(refresh)
}
3.2 就业信息推荐算法
基于学生专业和岗位标签的协同过滤算法:
python复制# services/recommend.py
from collections import defaultdict
import numpy as np
class JobRecommender:
def __init__(self, student_id):
self.student = self._get_student_profile(student_id)
self.similarity_threshold = 0.6
def _cosine_similarity(self, vec1, vec2):
dot = np.dot(vec1, vec2)
norm = np.linalg.norm(vec1) * np.linalg.norm(vec2)
return dot / norm if norm != 0 else 0
def recommend(self, n=10):
# 获取所有岗位的标签向量
all_jobs = JobPosition.objects.filter(
expire_time__gte=timezone.now()
).values('id', 'tags')
# 计算相似度
recommendations = []
student_tags = self.student['tags']
for job in all_jobs:
similarity = self._cosine_similarity(
student_tags,
job['tags']
)
if similarity >= self.similarity_threshold:
recommendations.append((job['id'], similarity))
# 按相似度排序返回TopN
return sorted(recommendations, key=lambda x: -x[1])[:n]
4. 性能优化实践
4.1 数据库查询优化
-
索引优化:
- 为所有外键字段添加索引
- 对组合查询字段建立复合索引,如
(major, grade) - 使用
explain分析慢查询
-
查询优化技巧:
python复制# 错误做法:N+1查询问题 students = Student.objects.all() for s in students: # 每次循环都查询数据库 print(s.department.name) # 正确做法:使用select_related/prefetch_related students = Student.objects.select_related( 'department' ).prefetch_related( 'job_applications' )
4.2 缓存策略
采用三级缓存架构:
- 热点数据:Redis缓存(如首页推荐岗位)
- 静态资源:CDN缓存
- 浏览器缓存:设置合适的Cache-Control
配置示例:
python复制CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/1",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"SOCKET_CONNECT_TIMEOUT": 5, # 秒
"SOCKET_TIMEOUT": 5, # 秒
}
}
}
# 视图层使用缓存
@method_decorator(cache_page(60 * 15), name='dispatch')
class JobListView(ListAPIView):
queryset = JobPosition.objects.all()
serializer_class = JobPositionSerializer
5. 安全防护措施
5.1 常见Web安全防护
-
XSS防护:
- 前端使用vue-sanitize过滤HTML
- Django模板自动转义特殊字符
- 设置HttpOnly Cookie
-
CSRF防护:
python复制# settings.py CSRF_COOKIE_SECURE = True # 仅HTTPS传输 CSRF_COOKIE_HTTPONLY = True CSRF_TRUSTED_ORIGINS = ['https://yourdomain.com'] -
SQL注入防护:
- 永远使用ORM或参数化查询
- 禁止拼接SQL语句
5.2 数据安全策略
-
敏感字段加密存储:
python复制from cryptography.fernet import Fernet class Student(models.Model): _phone = models.BinaryField(blank=True) @property def phone(self): return decrypt(self._phone) if self._phone else None @phone.setter def phone(self, value): self._phone = encrypt(value) -
定期审计日志:
python复制# middleware/audit.py class AuditMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): response = self.get_response(request) if request.user.is_authenticated: AuditLog.objects.create( user=request.user, path=request.path, method=request.method, status_code=response.status_code, ip=request.META.get('REMOTE_ADDR') ) return response
6. 部署方案
6.1 生产环境部署
推荐使用Docker Compose部署:
yaml复制version: '3.8'
services:
db:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
MYSQL_DATABASE: ${DB_NAME}
MYSQL_USER: ${DB_USER}
MYSQL_PASSWORD: ${DB_PASSWORD}
volumes:
- mysql_data:/var/lib/mysql
ports:
- "3306:3306"
restart: always
redis:
image: redis:6
ports:
- "6379:6379"
volumes:
- redis_data:/data
restart: always
web:
build: .
command: gunicorn config.wsgi:application --bind 0.0.0.0:8000
volumes:
- static_volume:/app/static
environment:
- DJANGO_SETTINGS_MODULE=config.settings.prod
depends_on:
- db
- redis
ports:
- "8000:8000"
restart: always
volumes:
mysql_data:
redis_data:
static_volume:
6.2 性能监控配置
使用Prometheus+Grafana监控:
-
安装django-prometheus:
python复制INSTALLED_APPS += ['django_prometheus'] MIDDLEWARE.insert(0, 'django_prometheus.middleware.PrometheusBeforeMiddleware') MIDDLEWARE.append('django_prometheus.middleware.PrometheusAfterMiddleware') -
配置Grafana仪表盘监控:
- QPS
- 接口响应时间P99
- 数据库连接池使用率
- 缓存命中率
7. 开发经验与避坑指南
7.1 跨域问题解决方案
前后端分离常见跨域问题,推荐配置:
python复制# settings.py
CORS_ALLOWED_ORIGINS = [
"https://your-frontend.com",
"http://localhost:8080",
]
CORS_EXPOSE_HEADERS = ['Content-Disposition']
CORS_ALLOW_CREDENTIALS = True
# 或者使用nginx反向代理解决
location /api/ {
proxy_pass http://backend:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
7.2 文件上传优化
大文件上传需要特殊处理:
- 前端分片上传
- 后端使用chunked接收:
python复制@api_view(['POST']) def upload_resume(request): chunk = request.FILES.get('chunk') chunk_number = request.POST.get('chunkNumber') total_chunks = request.POST.get('totalChunks') # 保存分片到临时目录 temp_dir = os.path.join(MEDIA_ROOT, 'temp', request.user.id) os.makedirs(temp_dir, exist_ok=True) chunk_path = os.path.join(temp_dir, f'chunk-{chunk_number}') with open(chunk_path, 'wb') as f: for chunk_part in chunk.chunks(): f.write(chunk_part) # 全部分片上传完成后合并 if int(chunk_number) == int(total_chunks) - 1: merge_files(temp_dir, request.user.resume.path) return Response({'status': 'success'})
7.3 定时任务管理
使用Celery处理异步任务:
python复制# tasks.py
from celery import shared_task
from django.core.mail import send_mail
@shared_task(bind=True)
def send_job_alert(self, user_id):
user = User.objects.get(id=user_id)
jobs = JobRecommender(user.id).recommend()
send_mail(
'最新岗位推荐',
render_to_string('emails/job_alert.html', {'jobs': jobs}),
'noreply@yourdomain.com',
[user.email],
fail_silently=False,
)
配置Celery Beat定时发送:
python复制# celery.py
app.conf.beat_schedule = {
'send-daily-job-alerts': {
'task': 'app.tasks.send_job_alert',
'schedule': crontab(hour=9, minute=0), # 每天上午9点
},
}
这个项目从技术选型到最终部署,每个环节都需要考虑教育场景的特殊性。比如学生信息的隐私保护、高并发选课期间的性能保障、与学校现有系统的数据对接等。我在实际开发中最大的体会是:教育类系统的开发不能只追求技术先进性,更要考虑易用性和稳定性,因为最终用户可能是对计算机不太熟悉的行政老师和学生。