作者主页:编程指南针
简介:Java领域优质创作者、CSDN博客专家 Java项目、简历模板、学习资料、面试题库、技术互助
文末获取源码
目录
一,项目概述:
项目编码:BS-PT-059
本项目基于Springboot 开发实现了一个求职招聘网站,系统分为前端求职招聘和后台数据管理后台。主要分为四个角以:管理员,求职者,公司管理员,公司HR,不同的角色进入系统有不同的功能操作。用户身份可以在后台管理设定。系统功能完整,界面美观大方,适合做毕业设计使用。
运行环境:
开发工具:IDEA或ECLIPSE
数据库:MYSQL+REDIS
开发技术:Springboot+mybatis+mybatisPlus+shiro
前端开发:AJAX+Jquery+layui
2.1 功能需求
2.1.1 系统划分
编辑
2.1.1.1 用户角色划分
- 求职者
登录本网站的一种用户,可以检索并查看网站入驻的公司及其发布的岗位信息,创建自己的简历,与招聘者进行联系。
- 应聘者
2.1、HR
公司下的某一个HR,可以发布新岗位和取消自己发布的岗位招聘
2.2、公司管理员
公司管理员,填写公司相关信息入驻网站后成为该角色,可以管理本公司发布的所有岗位,以及管理所有员工
3、管理员
可以查看站内相关数据,对私信、系统、设置进行管理。
2.1.1.2 前台服务的用例图及说明
- 招聘者功能
编辑
- 查看个人信息:查看自己账号的基本信息及修改
- 修改密码:修改自己账号的登录密码
- 私信:与求职者私信
- 公司入驻:如果是第一次登录该网站,用户可以输入公司信息,进行入驻网站,随后可发布岗位
- 岗位管理:对岗位进行发布、取消、编辑等操作
- 员工管理:权限允许的前提下,管理自己公司内所有的hr
- HR信息:查看自己的基本信息
- 求职者功能:
编辑
- 查看个人信息:查看自己账号的基本信息及修改
- 修改密码:修改自己账号的登录密码
- 私信:对感兴趣岗位的HR进行联系
- 个人简历:创建自己的简历,供HR查看
- 搜索岗位:搜索自己感兴趣的岗位
- 搜索公司:搜索自己感兴趣的公司
2.1.1.3 管理员后台用例图
编辑
- 查看个人信息:查看自己账号的基本信息及修改
- 修改密码:修改自己账号的登录密码
- 公司管理:管理站内所有入驻的公司
- 用户管理:管理站内所有用户
- 岗位管理:管理站内所有岗位
- 简历管理:管理站内所有简历
- 数据字典:管理站内数据字典
- 私信管理:查看所有用户的聊天关系、聊天记录等 三、数据库设计
3.1 实体关系图
编辑
表结构暂略
五、系统界面
- 首页:
编辑
2.登录界面:
编辑
3.注册界面
编辑
4.岗位查看搜索
编辑
5.公司查看界面
编辑
6.HR管理界面
编辑
7.岗位管理界面
编辑
8.员工管理
编辑
9.个人简历
编辑
10.管理员后台管理
编辑
系统部分核心代码:
package com.iurac.recruit.controller; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ReUtil; import cn.hutool.core.util.StrUtil; import com.iurac.recruit.entity.Job; import com.iurac.recruit.entity.User; import com.iurac.recruit.exception.ManageException; import com.iurac.recruit.security.RedisCacheManager; import com.iurac.recruit.service.UserService; import com.iurac.recruit.util.ImageUtil; import com.iurac.recruit.util.Result; import com.iurac.recruit.util.SaltUtil; import com.iurac.recruit.util.TableResult; import com.iurac.recruit.vo.PageResultVo; import com.sun.org.apache.regexp.internal.RE; import com.sun.org.apache.xpath.internal.operations.Mult; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.authz.annotation.RequiresRoles; import org.apache.shiro.crypto.hash.Md5Hash; import org.apache.shiro.subject.Subject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpSession; import java.io.IOException; import java.util.Objects; @Controller public class UserController { @Autowired private RedisCacheManager redisCacheManager; @Autowired private UserService userService; @GetMapping({"/","/index"}) public String toIndex(Model model){ User user = (User) SecurityUtils.getSubject().getPrincipal(); if(ObjectUtil.isNotNull(user)){ model.addAttribute("userInfo",user); } return "index"; } @GetMapping("/login") public String toLogin(){ return "login"; } @GetMapping("/register") public String toRegister(){ return "register"; } @PostMapping("/login") @ResponseBody public Result login(String username, String password, String code, HttpSession session) { String codes = (String) session.getAttribute("KAPTCHA_SESSION_KEY"); if (StrUtil.hasBlank(codes)) { throw new RuntimeException("验证码已超时!"); } String msg = ""; try { if (codes.equalsIgnoreCase(code)){ //获取主体对象 Subject subject = SecurityUtils.getSubject(); subject.login(new UsernamePasswordToken(username, password)); return Result.succ("登录成功"); }else{ throw new RuntimeException("验证码错误!"); } } catch (UnknownAccountException e) { e.printStackTrace(); msg="用户名错误!"; } catch (IncorrectCredentialsException e) { e.printStackTrace(); msg="密码错误!"; }catch (Exception e){ e.printStackTrace(); msg=e.getMessage(); } return Result.fail(msg); } @GetMapping("logout") public String logout() { Subject subject = SecurityUtils.getSubject(); subject.logout(); return "login"; } @PostMapping("/register") @ResponseBody public Result register(User user, @RequestParam("role")String role) throws Exception { user.setImg("default.png"); userService.register(user,role); return Result.succ("操作成功"); } @PostMapping("/user/update") @ResponseBody public Result updateUserInfo(@RequestParam(value = "phone",required = false) String phone, @RequestParam(value = "email",required = false) String email, @RequestParam(value="imgFile",required = false) MultipartFile file) throws Exception { User user = (User) SecurityUtils.getSubject().getPrincipal(); redisCacheManager.getCache("authenticationCacheName").remove(user); if(!StrUtil.hasBlank(phone)){ if(ReUtil.isMatch("(13\\d|14[579]|15[^4\\D]|17[^49\\D]|18\\d)\\d{8}", phone)) { user.setPhone(phone); }else { return Result.fail("请输入正确的手机号"); } } if(!StrUtil.hasBlank(email)){ if(ReUtil.isMatch("\\w[-\\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\\.)+[A-Za-z]{2,14}", email)){ user.setEmail(email); }else { return Result.fail("请输入正确的邮箱地址"); } } if(ObjectUtil.isNotNull(file) && !file.isEmpty()){ String originalFileName = file.getOriginalFilename(); String imgName = user.getImg().equals("default.png")?ImageUtil.getFileName(originalFileName.substring(originalFileName.lastIndexOf("."))): user.getImg(); user.setImg(imgName); ImageUtil.saveImage(file,user.getImg(),"userIcon"); } if(!userService.updateById(user)){ return Result.fail("系统错误"); } redisCacheManager.getCache("authenticationCacheName").put(user.getUsername(),user); return Result.succ("操作成功"); } @PutMapping("/user/updatePassword/{password}") @ResponseBody public Result updateUserInfo(@PathVariable("password") String password) throws Exception { User user = (User) SecurityUtils.getSubject().getPrincipal(); if(ReUtil.isMatch("[\\S]{6,12}", password)) { Md5Hash md5Hash = new Md5Hash(password,user.getSalt(),1024); if(md5Hash.toHex().equals(user.getPassword())){ return Result.fail("请输入新密码"); } redisCacheManager.getCache("authorizationCacheName").remove(user.toString()); redisCacheManager.getCache("authenticationCacheName").remove(user); user.setPassword(md5Hash.toHex()); System.out.println(user.getPassword()); }else { return Result.fail("密码必须6到12位,且不能出现空格"); } if(!userService.updateById(user)){ return Result.fail("系统错误"); } redisCacheManager.getCache("authenticationCacheName").put(user.getUsername(),user); return Result.succ("操作成功"); } @RequiresRoles("admin") @ResponseBody @GetMapping("/user/getByCondition") public TableResult<User> getByCondition(@RequestParam("page")Long page, @RequestParam("limit")Long limit, @RequestParam("username")String username, @RequestParam("role")String role, @RequestParam("startDate")String startDate, @RequestParam(value = "endDate",required = false)String endDate, @RequestParam("locked")String locked){ PageResultVo<User> pageResultVo = userService.getByCondition(page,limit,username,role,locked,startDate,endDate); return new TableResult(0,"",pageResultVo.getTotal(),pageResultVo.getRecords()); } @RequiresRoles("admin") @ResponseBody @PostMapping("/user/save") public Result saveUser(@RequestParam("username")String username, @RequestParam("role")String[] role, @RequestParam("password")String password, @RequestParam(value = "imgFile",required = false) MultipartFile file, @RequestParam("phone")String phone, @RequestParam("email")String email) throws IOException, ManageException { if(StrUtil.hasEmpty(username,password,phone,email) || role.length<=0){ return Result.fail("请输入完整信息,避免输入空格"); } if(!ReUtil.isMatch("[\\S]{6,12}", password)) { return Result.fail("密码必须6到12位,且不能出现空格"); } if(!ReUtil.isMatch("(13\\d|14[579]|15[^4\\D]|17[^49\\D]|18\\d)\\d{8}", phone)) { return Result.fail("请输入正确的手机号"); } if(!ReUtil.isMatch("\\w[-\\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\\.)+[A-Za-z]{2,14}", email)){ return Result.fail("请输入正确的邮箱地址"); } User user = new User(); user.setId(IdUtil.simpleUUID()); user.setUsername(username); user.setCreateTime(DateUtil.now()); user.setSalt(SaltUtil.getSalt(8)); Md5Hash md5Hash = new Md5Hash(password, user.getSalt(), 1024); user.setPassword(md5Hash.toHex()); user.setLocked("0"); user.setPhone(phone); user.setEmail(email); if(ObjectUtil.isNotNull(file) && !file.isEmpty()){ String originalFileName = file.getOriginalFilename(); user.setImg(ImageUtil.getFileName(originalFileName.substring(originalFileName.lastIndexOf(".")))); ImageUtil.saveImage(file,user.getImg(),"userIcon"); }else { user.setImg("default.png"); } userService.saveUser(user,role); return Result.succ("操作成功"); } @RequiresRoles("admin") @ResponseBody @PostMapping("/user/update/{id}") public Result updateUser(@PathVariable("id")String id,@RequestParam("role")String[] role, @RequestParam("password")String password, @RequestParam(value = "imgFile",required = false) MultipartFile file, @RequestParam("phone")String phone, @RequestParam("email")String email) throws IOException, ManageException { if(StrUtil.hasEmpty(password,phone,email) || role.length<=0){ return Result.fail("请输入完整信息,避免输入空格"); } if(!ReUtil.isMatch("[\\S]{6,12}", password)) { return Result.fail("密码必须6到12位,且不能出现空格"); } if(!ReUtil.isMatch("(13\\d|14[579]|15[^4\\D]|17[^49\\D]|18\\d)\\d{8}", phone)) { return Result.fail("请输入正确的手机号"); } if(!ReUtil.isMatch("\\w[-\\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\\.)+[A-Za-z]{2,14}", email)){ return Result.fail("请输入正确的邮箱地址"); } User user = userService.getById(id); redisCacheManager.getCache("authorizationCacheName").remove(user.toString()); redisCacheManager.getCache("authenticationCacheName").remove(user); user.setSalt(SaltUtil.getSalt(8)); Md5Hash md5Hash = new Md5Hash(password, user.getSalt(), 1024); user.setPassword(md5Hash.toHex()); user.setPhone(phone); user.setEmail(email); if(ObjectUtil.isNotNull(file) && !file.isEmpty()){ String originalFileName = file.getOriginalFilename(); user.setImg(ImageUtil.getFileName(originalFileName.substring(originalFileName.lastIndexOf(".")))); ImageUtil.saveImage(file,user.getImg(),"userIcon"); } userService.updateUser(user,role); return Result.succ("操作成功"); } @RequiresRoles("admin") @ResponseBody @PostMapping("/user/delete/{id}") public Result deleteUser(@PathVariable("id")String id) throws ManageException { userService.deleteUser(id); return Result.succ("操作成功"); } @RequiresRoles("admin") @ResponseBody @PostMapping("/user/lock/{id}") public Result lockUser(@PathVariable("id")String id) throws ManageException { User user = userService.getById(id); user.setLocked("1".equals(user.getLocked())?"0":"1"); userService.updateById(user); return Result.succ("操作成功"); } }
package com.iurac.recruit.controller; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ReUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.iurac.recruit.entity.Company; import com.iurac.recruit.entity.Resume; import com.iurac.recruit.entity.User; import com.iurac.recruit.exception.ManageException; import com.iurac.recruit.service.ResumeService; import com.iurac.recruit.util.ImageUtil; import com.iurac.recruit.util.Result; import com.iurac.recruit.util.TableResult; import com.iurac.recruit.vo.PageResultVo; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authz.annotation.RequiresRoles; import org.apache.shiro.authz.annotation.RequiresUser; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; import org.springframework.stereotype.Controller; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; /** * <p> * 前端控制器 * </p> * * @author iurac * @since 2021-06-03 */ @Controller public class ResumeController { @Autowired private ResumeService resumeService; @PostMapping("/resume/saveOrUpdate") @ResponseBody public Result saveOrUpdate(Resume resume, @RequestParam(value="imgFile",required = false) MultipartFile file) throws Exception { if(StrUtil.hasBlank(resume.getName(),resume.getTechnology(),resume.getSalary(), resume.getMajor(),resume.getJob(), resume.getIntroduction(),resume.getExperience(),resume.getCollege(),resume.getBirth(),resume.getEducation(), resume.getPolitical(),resume.getMarriage(),resume.getSex())){ return Result.fail("请输入完成信息,避免输入空格"); } if(!ReUtil.isMatch("(13\\d|14[579]|15[^4\\D]|17[^49\\D]|18\\d)\\d{8}", resume.getPhone())) { return Result.fail("请输入正确的手机号"); } if(!ReUtil.isMatch("\\w[-\\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\\.)+[A-Za-z]{2,14}", resume.getEmail())){ return Result.fail("请输入正确的邮箱地址"); } User user = (User) SecurityUtils.getSubject().getPrincipal(); resume.setUserId(user.getId()); QueryWrapper<Resume> queryWrapper = new QueryWrapper<>(); queryWrapper.eq("user_id",user.getId()); Resume exitedResume = resumeService.getOne(queryWrapper); resume.setPhoto("default.png"); boolean isUpdate = true; if(ObjectUtil.isNull(exitedResume)){//判断是新增还是更新 resume.setId(IdUtil.simpleUUID()); isUpdate = false; }else { resume.setId(exitedResume.getId()); resume.setPhoto(exitedResume.getPhoto()); } if(ObjectUtil.isNotNull(file) && !file.isEmpty()){ String originalFileName = file.getOriginalFilename(); String photoName = resume.getPhoto().equals("default.png")?ImageUtil.getFileName(originalFileName.substring(originalFileName.lastIndexOf("."))): resume.getPhoto(); resume.setPhoto(photoName); ImageUtil.saveImage(file,resume.getPhoto(),"photo"); } boolean flag = isUpdate?resumeService.updateById(resume):resumeService.save(resume); if(flag){ return Result.succ("操作成功"); }else { return Result.fail("系统错误"); } } @RequiresRoles("admin") @ResponseBody @GetMapping("/resume/getByCondition") public TableResult<Resume> getByCondition(@RequestParam("page")Long page, @RequestParam("limit")Long limit, @RequestParam("username")String username){ PageResultVo<Resume> pageResultVo = resumeService.getByCondition(page,limit,username); return new TableResult(0,"",pageResultVo.getTotal(),pageResultVo.getRecords()); } @RequiresRoles("admin") @ResponseBody @PostMapping("/resume/update/{id}") public Result updateResume(@PathVariable("id")String id, @RequestParam(value = "imgFile",required = false) MultipartFile file, Resume resume) throws IOException { if(StrUtil.hasEmpty(resume.getSex(),resume.getMarriage(),resume.getPolitical(),resume.getEducation(), resume.getEmail(),resume.getAge(),resume.getPhone(),resume.getName(),resume.getExperience(), resume.getTechnology(),resume.getSalary(),resume.getMajor(),resume.getIntroduction(),resume.getCollege(), resume.getBirth(),resume.getJob())){ return Result.fail("请输入完整信息,避免输入空格"); } Resume exitedResume = resumeService.getById(id); resume.setId(id); resume.setUserId(exitedResume.getUserId()); resume.setPhoto(exitedResume.getPhoto()); if(ObjectUtil.isNotNull(file) && !file.isEmpty()){ String originalFileName = file.getOriginalFilename(); resume.setPhoto(ImageUtil.getFileName(originalFileName.substring(originalFileName.lastIndexOf(".")))); ImageUtil.saveImage(file,resume.getPhoto(),"companyIcon"); } return resumeService.updateById(resume)?Result.succ("操作成功"):Result.fail("操作失败"); } @RequiresRoles("admin") @ResponseBody @PostMapping("/resume/delete/{id}") public Result deleteResume(@PathVariable("id")String id) { resumeService.removeById(id); return Result.succ("操作成功"); } /** * * @param id 用户ID * @param model * @return */ @RequiresUser @GetMapping("/resume/detail/{id}") public String detail(@PathVariable("id")String id, Model model) { Resume resume = resumeService.getByUserId(id); model.addAttribute("resumeInfo",resume); return "service/detail_resume"; } }