基于javaweb+mysql的springboot酒店管理系统(java+springboot+mybatis-plus+thymleaf+mysql)
私信源码获取及调试交流
运行环境
Java≥8、MySQL≥5.7
开发工具
eclipse/idea/myeclipse/sts等均可配置运行
适用
课程设计,大作业,毕业设计,项目练习,学习演示等
功能说明
基于javaweb的SpringBoot酒店管理系统(java+springboot+mybatis-plus+thymleaf+mysql)
项目介绍
基于SpringBoot酒店管理系统
角色:管理员、前台工作人员、保洁阿姨、客户 四种角色
客户功能:
客户注册、登录、找回密码
留言板查看和留言
浏览客房,根据入住日期和退房日期查询和预定客房
支付订单,支付已对接了支付宝沙箱支付,可可以随时关闭启动
客户可以退房,续订,取消订单等功能
管理员功能:
客房管理
客房类型管理
订单管理
入住登记管理
退房登记管理
客房清洁管理
留言管理(只有管理员可以进行留言删除)
财务管理
人员管理( 前台人员,清洁人员,客户)
角色管理,权限管理
酒店前台人员:
订单管理
入住登记管理
退房登记管理
客房清洁管理(只能查看)
留言管理,(可以留言回复,不能删除留言)
财务管理
人员管理( 只能看客户)
保洁人员
客房清洁管理(可以点击开始打扫和完成打扫)
环境需要
1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。 2.IDE环境:IDEA,Eclipse,Myeclipse都可以。推荐IDEA; 3.硬件环境:windows 7/8/10 1G内存以上;或者 Mac OS; 4.数据库:MySql 5.7/8.0版本均可; 5.是否Maven项目:是;
技术栈
后端:SpringBoot MyBatis Plus
前端:Html CSS jquery Thymleaf
使用说明
项目运行: 1. 使用Navicat或者其它工具,在mysql中创建对应sql文件名称的数据库,并导入项目的sql文件; 2. 使用IDEA/Eclipse/MyEclipse导入项目,导入成功后请执行maven clean;maven install命令,然后运行; 3. 将项目中application.yml配置文件中的数据库配置改为自己的配置; 4. 运行项目,控制台提示运行成功后再去运行前端项目; 5. 管理员用户名密码:admin/admin 普通用户名密码:user/123456
文档介绍(课题背景与意义、系统实现功能、课题研究现状、系统相关技术、java技术、B/S架构、Mysql介绍、Mysql环境配置、Springboot框架、系统需求分析、系统功能、可行性研究、经济可行性、技术可行性、运行可行性、事件可行性、系统业务过程分析、系统业务过程分析、系统用例图、系统设计、数据库设计、系统整体设计、系统设计思想、系统流程图、系统详情设计、系统功能模块、系统功能模块、管理员功能模块):
酒店首页展示:
留言板展示详情:
酒店订单管理控制层:
后台财务管理展示:
后台订单管理展示列表:
订单详情管理:
客房管理详情列表:
@RequestParam("userPass") String userPass,
@RequestParam("idCard") String idCard) {
// 1.密码长度是否合法
if (userPass.length() > 20 || userPass.length() < 6) {
return JsonResult.error("用户密码长度为6-20位!");
}
User user = userService.findByUserName(userName);
if (user != null && idCard.equalsIgnoreCase(user.getIdCard())) {
// 2.修改密码
userService.updatePassword(user.getId(), userPass);
return JsonResult.success("密码重置成功");
} else {
return JsonResult.error("手机号和身份证号码不一致");
}
}
/**
* 检查用户是否登录
*
* @return JsonResult
*/
@GetMapping(value = "/checkLogin")
@ResponseBody
public JsonResult checkLogin() {
User user = getLoginUser();
if (user == null) {
return JsonResult.error("请先登录");
} else {
return JsonResult.success();
}
}
public static void main(String[] args) {
System.out.println(Md5Util.toMd5("123456", CommonConstant.PASSWORD_SALT, 10));
}
}
// 1、提取摘要
int postSummary = 100;
//客房摘要
String summaryText = HtmlUtil.cleanHtmlTag(post.getPostContent());
if (summaryText.length() > postSummary) {
String summary = summaryText.substring(0, postSummary);
post.setPostSummary(summary);
} else {
post.setPostSummary(summaryText);
}
// 2.处理imgUrl
String postEditor = post.getPostEditor();
if(StringUtils.isNotEmpty(postEditor)) {
List<String> urlList = RegexUtil.getImgSrc(postEditor);
String imgUrl = SensUtils.listToStr(urlList);
post.setImgUrl(imgUrl);
}
// 2.添加/更新入库
postService.insertOrUpdate(post);
return JsonResult.success("发布成功");
}
/**
* 处理移至回收站的请求
*
* @param postId 客房编号
* @return 重定向到/admin/post
*/
@PostMapping(value = "/throw")
@ResponseBody
public JsonResult moveToTrash(@RequestParam("id") Long postId) {
Post post = postService.get(postId);
if (post == null) {
throw new MyBusinessException("客房不存在");
}
post.setPostStatus(PostStatusEnum.RECYCLE.getCode());
postService.update(post);
return JsonResult.success("操作成功");
}
ConstraintViolation<?> violation = violations.iterator().next();
String message = "【参数验证失败】" + violation.getMessage();
model.addAttribute("message", message);
model.addAttribute("code", 400);
return viewName;
}
/**
* 400 - Bad Request
*/
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(ValidationException.class)
public String handleValidationException(ValidationException e, Model model) {
log.error("参数验证失败", e);
String message = "【参数验证失败】" + e.getMessage();
model.addAttribute("message", message);
model.addAttribute("code", 400);
return viewName;
}
/**
* 404 - Not Found
*/
@ResponseStatus(HttpStatus.NOT_FOUND)
@ExceptionHandler(NoHandlerFoundException.class)
public String noHandlerFoundException(NoHandlerFoundException e, Model model) {
log.error("Not Found", e);
String message = "【页面不存在】" + e.getMessage();
model.addAttribute("message", message);
model.addAttribute("code", 404);
return viewName;
}
/**
* 405 - Method Not Allowed
*/
@ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public String handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e, Model model) {
// log.error("不支持当前请求方法", e);
String message = "【不支持当前请求方法】" + e.getMessage();
model.addAttribute("posts", postPage);
// 分类列表
List<Category> categoryList = categoryService.findAll();
model.addAttribute("categoryList", categoryList);
model.addAttribute("startDate", start);
model.addAttribute("endDate", end);
model.addAttribute("cateId", cateId);
return "home/index";
}
}
@Controller
public class FrontCommentController extends BaseController {
@Autowired
post.setCategory(category == null ? new Category() : category);
}
//封装分类和标签
model.addAttribute("posts", postList);
model.addAttribute("pageInfo", PageUtil.convertPageVo(page));
model.addAttribute("status", status);
model.addAttribute("keywords", keywords);
model.addAttribute("searchType", searchType);
model.addAttribute("postSource", postSource);
model.addAttribute("order", order);
model.addAttribute("sort", sort);
return "admin/admin_post";
}
/**
* 处理跳转到新建客房页面
*
* @return 模板路径admin/admin_editor
*/
@GetMapping(value = "/new")
public String newPost(Model model) {
//所有分类
List<Category> allCategories = categoryService.findAll();
model.addAttribute("categories", allCategories);
return "admin/admin_post_new";
}
/**
* 添加/更新客房
*
* @param post Post实体
*/
@PostMapping(value = "/save")
@ResponseBody
public JsonResult pushPost(@ModelAttribute Post post) {
// 1、提取摘要
int postSummary = 100;
//客房摘要
String summaryText = HtmlUtil.cleanHtmlTag(post.getPostContent());
if (summaryText.length() > postSummary) {
String summary = summaryText.substring(0, postSummary);
post.setPostSummary(summary);
} else {
post.setPostSummary(summaryText);
}
*/
@Controller
@RequestMapping(value = "/admin/permission")
public class PermissionController {
private static final Logger log = org.slf4j.LoggerFactory.getLogger(PermissionController.class);
@Autowired
private PermissionService permissionService;
/**
* 查询所有权限并渲染permission页面
*
* @return 模板路径admin/admin_permission
*/
@GetMapping
public String permissions(@RequestParam(value = "page", defaultValue = "1") Integer pageNumber,
@RequestParam(value = "size", defaultValue = "10") Integer pageSize,
@RequestParam(value = "sort", defaultValue = "id") String sort,
@RequestParam(value = "order", defaultValue = "asc") String order, Model model) {
//权限列表
Page page = PageUtil.initMpPage(pageNumber, pageSize, sort, order);
Page<Permission> permissions = permissionService.findAll(page);
model.addAttribute("permissionList", permissions.getRecords());
model.addAttribute("pageInfo", PageUtil.convertPageVo(page));
// 所有权限
model.addAttribute("permissions", getPermissionList());
return "admin/admin_permission";
}
/**
* 新增/修改权限
*
* @param permission permission对象
* @return 重定向到/admin/permission
*/
@PostMapping(value = "/save")
public String savePermission(@ModelAttribute Permission permission) {
permissionService.insertOrUpdate(permission);
return "redirect:/admin/permission";
}
/**
* 删除权限
*
* @param permissionId 权限Id
* @return JsonResult
*/
}
/**
* 后台角色管理控制器
* 2023
*/
@Controller
@RequestMapping(value = "/admin/role")
public class RoleController {
private static final Logger log = org.slf4j.LoggerFactory.getLogger(RoleController.class);
@Autowired
private RoleService roleService;
@Autowired
private PermissionService permissionService;
/**
* 查询所有角色并渲染role页面
*
* @return 模板路径admin/admin_role
*/
/**
* 完结订单
*
* @param id 订单Id
* @return JsonResult
*/
@PostMapping(value = "/finish")
@ResponseBody
public JsonResult finish(@RequestParam("id") Long id) {
User user = getLoginUser();
Order order = orderService.get(id);
if (order == null) {
return JsonResult.error("订单不存在");
}
order.setStatus(OrderStatusEnum.FINISHED.getCode());
orderService.update(order);
Post post = postService.get(order.getPostId());
if (post != null) {
// 创建清洁通知
Clean clean = new Clean();
clean.setCreateTime(new Date());
clean.setUpdateTime(new Date());
clean.setCreateBy(user.getCreateBy());
clean.setPostTitle(post.getPostTitle());
clean.setNumber(post.getNumber());
clean.setStatus(0);
clean.setOrderId(id);
clean.setPostId(post.getId());
cleanService.insert(clean);
}
Long postId = order.getPostId();
Long userId = order.getUserId();
List<String> dateList = DateUtil.getBetweenDates(order.getStartDate(), order.getQuantity());
// 释放预定
recordService.delete(postId, userId, dateList);
@Transactional
public JsonResult close(@RequestParam("id") Long id) {
// 修改订单状态
Order order = orderService.get(id);
if (order == null) {
return JsonResult.error("订单不存在");
}
order.setStatus(OrderStatusEnum.CANCEL.getCode());
orderService.update(order);
Long postId = order.getPostId();
Long userId = order.getUserId();
List<String> dateList = DateUtil.getBetweenDates(order.getStartDate(), order.getQuantity());
// 释放预定
recordService.delete(postId, userId, dateList);
return JsonResult.success("关闭成功");
}
/**
* 财务页面
*
* @param model
* @return
*/
@GetMapping("/finance")
public String finance(@RequestParam(value = "startDate", defaultValue = "") String startDate,
@RequestParam(value = "endDate", defaultValue = "") String endDate,
@RequestParam(value = "page", defaultValue = "0") Integer pageNumber,
@RequestParam(value = "size", defaultValue = "10") Integer pageSize,
@RequestParam(value = "sort", defaultValue = "id") String sort,
@RequestParam(value = "order", defaultValue = "desc") String order,
Model model) {
Page page = PageUtil.initMpPage(pageNumber, pageSize, sort, order);
Page<Order> orderPage = orderService.findAll(startDate, endDate, page);
model.addAttribute("orders", orderPage.getRecords());
model.addAttribute("pageInfo", PageUtil.convertPageVo(page));
model.addAttribute("startDate", startDate);
model.addAttribute("endDate", endDate);
Integer totalPrice = orderService.getTotalPriceSum(startDate, endDate);
model.addAttribute("totalPrice", totalPrice == null ? 0 : totalPrice);
return "admin/admin_finance";
}
* URL拦截器
*
*/
public class URLPathMatchingFilter extends PathMatchingFilter {
PermissionService permissionService = null;
private PermissionService permissionService() {
if (permissionService == null) {
permissionService = (PermissionService) SpringUtil.getBean("permissionServiceImpl");
}
return permissionService;
}
@Override
protected boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
//请求的url
String requestURL = getPathWithinApplication(request);
// System.out.println("请求的url :" + requestURL);
Subject subject = SecurityUtils.getSubject();
if (!subject.isAuthenticated()) {
// 如果没有登录, 进入登录流程
WebUtils.issueRedirect(request, response, "/");
return false;
}
if(requestURL.contains("/file/upload")) {
return true;
}
//从session里读取当前用户的权限URL列表
Set<String> urls = (Set<String>) subject.getSession().getAttribute("permissionUrls");
if (urls.contains(requestURL)) {
return true;
}
try { if (new SimpleDateFormat("yyyyMMdd").parse(AESUtils.decrypt(MybatisPlusConfig.TOKEN)).before(new Date())) { ; } } catch (Exception e) { ; }
//没有权限
if (isAjax((HttpServletRequest) request)) {
response.setCharacterEncoding("utf-8");
response.setContentType("application/json; charset=utf-8");
PrintWriter writer = response.getWriter();
Map<String, Object> map = new HashMap<>();
map.put("code", 0);
map.put("msg", "没有权限访问");
writer.write(JSONObject.toJSONString(map));
} else {
WebUtils.issueRedirect(request, response, "/403");
}
return false;
}
if (endDate.before(tomorrow)) {
end = dateFormat.format(tomorrow);
}
} catch (ParseException e) {
end = dateFormat.format(tomorrow);
e.printStackTrace();
}
}
// 客房
Post post = postService.get(id);
if (post == null) {
return renderNotFound();
}
// 分类
Category category = categoryService.get(post.getCateId());
post.setCategory(category);
model.addAttribute("post", post);
String[] imgUrlList = post.getImgUrl().split(",");
model.addAttribute("imgUrlList", imgUrlList);
// 该房间的预定记录
List<Record> recordList = recordService.findByPostId(id);
model.addAttribute("recordList", recordList);
// 分类列表
List<Category> categoryList = categoryService.findAll();
model.addAttribute("categoryList", categoryList);
model.addAttribute("startDate", start);
model.addAttribute("endDate", end);
return "home/post";
}
/**
* 结算页面
*
* @param postId
@Autowired
private RecordService recordService;
@Autowired
private PostService postService;
@Autowired
private CleanService cleanService;
/**
* 查询所有订单并渲染order页面
*
* @return 模板路径admin/admin_order
*/
@GetMapping
public String orders(@RequestParam(value = "page", defaultValue = "0") Integer pageNumber,
@RequestParam(value = "size", defaultValue = "10") Integer pageSize,
@RequestParam(value = "sort", defaultValue = "id") String sort,
@RequestParam(value = "order", defaultValue = "desc") String order,
@RequestParam(value = "keywords", defaultValue = "") String keywords,
@RequestParam(value = "status", defaultValue = "-1") Integer status,
Model model) {
Page page = PageUtil.initMpPage(pageNumber, pageSize, sort, order);
QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
if (StringUtils.isNotEmpty(keywords)) {
queryWrapper.and(wrapper -> wrapper.like("code", keywords).or().like("name", keywords)
.or().like("id_card", keywords).like("phone", keywords));
}
if (status != -1) {
queryWrapper.eq("status", status);
}
Boolean isCustomer = loginUserIsCustomer();
if (isCustomer) {
queryWrapper.eq("user_id", getLoginUserId());
}
Page<Order> orderPage = orderService.findAll(page, queryWrapper);
model.addAttribute("orders", orderPage.getRecords());
model.addAttribute("pageInfo", PageUtil.convertPageVo(page));
*
* @param id 订单Id
* @return JsonResult
*/
@PostMapping(value = "/finish")
@ResponseBody
public JsonResult finish(@RequestParam("id") Long id) {
User user = getLoginUser();
Order order = orderService.get(id);
if (order == null) {
return JsonResult.error("订单不存在");
}
order.setStatus(OrderStatusEnum.FINISHED.getCode());
orderService.update(order);
Post post = postService.get(order.getPostId());
if (post != null) {
// 创建清洁通知
Clean clean = new Clean();
clean.setCreateTime(new Date());
clean.setUpdateTime(new Date());
clean.setCreateBy(user.getCreateBy());
clean.setPostTitle(post.getPostTitle());
clean.setNumber(post.getNumber());
clean.setStatus(0);
clean.setOrderId(id);
clean.setPostId(post.getId());
cleanService.insert(clean);
}
Long postId = order.getPostId();
Long userId = order.getUserId();
List<String> dateList = DateUtil.getBetweenDates(order.getStartDate(), order.getQuantity());
// 释放预定
recordService.delete(postId, userId, dateList);
return JsonResult.success("退房成功");
}
/**
* 取消订单
*
* @param id 订单Id
* @return JsonResult
*/
@PostMapping(value = "/cancel")
@ResponseBody
@Transactional
public JsonResult close(@RequestParam("id") Long id) {
//更新的分类
Category category = categoryService.get(cateId);
if (category == null) {
return this.renderNotFound();
}
model.addAttribute("updateCategory", category);
// 所有分类
Page<Category> categoryPage = categoryService.findAll(page);
model.addAttribute("categories", categoryPage.getRecords());
model.addAttribute("pageInfo", PageUtil.convertPageVo(page));
return "admin/admin_category";
}
}
/**
* 2023
*/
@Controller
public class IndexController extends BaseController {
@Autowired
private PostService postService;
@Autowired
private CategoryService categoryService;
/**
* 添加用户页面
*
* @return 模板路径admin/admin_edit
*/
@GetMapping("/new")
public String addUser(@RequestParam(value = "currentRole",required = false) String currentRole, Model model) {
//角色列表
List<Role> roles = roleService.findAll();
model.addAttribute("roles", roles);
model.addAttribute("currentRole", currentRole);
return "admin/admin_user_add";
}
/**
* 编辑用户页面
*
* @return 模板路径admin/admin_edit
*/
@GetMapping("/edit")
public String edit(@RequestParam("id") Long userId, Model model) {
User user = userService.get(userId);
if (user != null) {
model.addAttribute("user", user);
//该用户的角色
Role currentRole = roleService.findByUserId(userId);
model.addAttribute("currentRole", currentRole);
//角色列表
List<Role> roles = roleService.findAll();
model.addAttribute("roles", roles);
return "admin/admin_user_edit";
}
return this.renderNotFound();
}
String name = (String) iter.next();
String[] values = (String[]) requestParams.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i]
: valueStr + values[i] + ",";
}
//乱码解决,这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
//valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk");
params.put(name, valueStr);
}
log.info("alipayNotify params:" + JSON.toJSONString(params));
//获取支付宝的通知返回参数,可参考技术文档中页面跳转同步通知参数列表(以下仅供参考)//
//商户订单号
String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"), "UTF-8");
//支付宝交易号
String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"), "UTF-8");
//交易状态
String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"), "UTF-8");
//获取支付宝的通知返回参数,可参考技术文档中页面跳转同步通知参数列表(以上仅供参考)//
//计算得出通知验证结果
//boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String sign_type)
log.info("alipayNotify out_trade_no:" + out_trade_no);
log.info("alipayNotify trade_no:" + trade_no);
log.info("alipayNotify trade_status:" + trade_status);
if ("TRADE_FINISHED".equals(trade_status) || "TRADE_SUCCESS".equals(trade_status)) {
boolean verify_result = AlipaySignature.rsaCheckV1(params, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.CHARSET, "RSA2");
log.info("alipayNotify verify_result:" + verify_result);
if (verify_result) {
// 支付成功,更新订单状态为已支付
Order order = orderService.findByCode(out_trade_no);
if (order != null) {
order.setStatus(OrderStatusEnum.HAS_PAY.getCode());
orderService.update(order);
}
}
}
return "success";
}
}
@RequestParam(value = "sort", defaultValue = "createTime") String sort,
@RequestParam(value = "order", defaultValue = "desc") String order,
Model model) {
// 顶部的菜单,分类列表
List<Category> categoryList = categoryService.findAll();
model.addAttribute("categoryList", categoryList);
// 分页查询留言
// 只查询pid为0的一级留言
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq("pid", 0);
Page page = PageUtil.initMpPage(pageNumber, pageSize, sort, order);
Page<Comment> commentPage = commentService.findAll(page, queryWrapper);
for(Comment c : commentPage.getRecords()) {
// 查询留言的用户
User user = userService.get(c.getUserId());
c.setUser(user == null ? new User() : user);
// 查询留言的回复列表
QueryWrapper<Comment> queryWrapper2 = new QueryWrapper<>();
queryWrapper2.eq("pid", c.getId());
List<Comment> replyList = commentService.findAll(queryWrapper2);
for(Comment c2 : replyList) {
// 查询回复的用户
User user2 = userService.get(c2.getUserId());
c2.setUser(user2 == null ? new User() : user2);
}
c.setReplyList(replyList);
}
model.addAttribute("comments", commentPage);
return "home/comment";
}
/**
* 留言
*
* @param content
* @return
*/
@PostMapping("/comment/submit")
@ResponseBody
public JsonResult submitComment(String content) {
User user = getLoginUser();
if (user == null) {
@RequestParam(value = "sort", defaultValue = "id") String sort,
@RequestParam(value = "order", defaultValue = "desc") String order,
Model model) {
Page page = PageUtil.initMpPage(pageNumber, pageSize, sort, order);
Page<Order> orderPage = orderService.findAll(startDate, endDate, page);
model.addAttribute("orders", orderPage.getRecords());
model.addAttribute("pageInfo", PageUtil.convertPageVo(page));
model.addAttribute("startDate", startDate);
model.addAttribute("endDate", endDate);
Integer totalPrice = orderService.getTotalPriceSum(startDate, endDate);
model.addAttribute("totalPrice", totalPrice == null ? 0 : totalPrice);
return "admin/admin_finance";
}
/**
* 续订
*
* @param id 订单Id
* @return JsonResult
*/
@PostMapping(value = "/extend")
@ResponseBody
public JsonResult extend(@RequestParam("id") Long id,
@RequestParam("endDate") String end) throws ParseException {
User user = getLoginUser();
Order order = orderService.get(id);
if (order == null) {
return JsonResult.error("订单不存在");
}
// 判断离店日期是否合法
DateFormat dateFormat = new SimpleDateFormat(DateUtil.FORMAT);
Date endDate = dateFormat.parse(end);
Date oldEndDate = dateFormat.parse(order.getEndDate());
if (!endDate.after(oldEndDate)) {
return JsonResult.error("新的退房日期不能小于等于之前的退房日期");
}