栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

基于前后端分离—宾馆管理系统(springboot+vue+mybatisplus+redis+elementUI)赋源码

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

基于前后端分离—宾馆管理系统(springboot+vue+mybatisplus+redis+elementUI)赋源码

一、 实现功能

除员工登录外功能外:

所有功能都要通过登录实现(安全方面 前端通过vue-router 和vuex实现页面访问拦截,后端通过mysql和redis缓存中校验用户合法性,判断其身份状态)

员工分为 管理员 和 前台职工

共有功能:

登录功能:

登录前检查状态 防止重复登录,能够判断身份 vue据此进入不同主页,同时将信息保存在redis中,减少sql与服务器压力且查询 校验方面更加便捷

普通员工功能
查看所有房间,查看剩余房间(可点击房间直接进行开房),查看营业中的房间,查看暂停营业的房间(维修,清理等等)
添加顾客信息(给客人进行登记 ),按条件查询顾客信息(可个根据 电话号码查询 、身份证号查询)、查询所有在住的人员信息,查询历史顾客信息、对顾客信息进行修改
开房,退房,办理会员,查询所有未完成的订单和已完成的订单,查询某个顾客的订单,退出登录

管理员功能
添加员工,修改员工信息,查看所有在线的员工,强制员工下线
添加房间,删除房间,修改房间,进入普通员工页面实现所有普通员工功能

二、库表设计

员工表

房间表


房间类型映射表

数据部分

顾客等级表

数据部分

订单表


数据

三。最终效果

springboot后端


vue前端:










管理员界面


源码地址

https://gitee.com/wang-yongyan188/HotelManger.git

后端具体流程

总共分为4个模块:
员工模块(负责进行一些安全方面 员工的登录认证,身份校验,员工的增改查)
顾客模块(负责将顾客信息存储,对顾客信息进行增删改查),
房间模块(对房间的增删改查)
订单模块(负责开房(增),退房信息记录(改),外键房间号,员工号,顾客编号 可根据订单获取办理业务的员工所有信息,该顾客以及同住人员的所有信息,房间的所有信息以及自身订单信息(查))
接口为restful形式
事先准备
建立一个maven项目,引入springboot父项目,web依赖,测试依赖,druid连接池,lombok,mybatis-plus,redis,hutool工具包
pom文件



    4.0.0

    org.example
    hotelsys
    1.0-SNAPSHOT
    
        org.springframework.boot
        spring-boot-starter-parent
        2.6.4
        
    
    
        9
        9
    
    
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
        
            org.projectlombok
            lombok
            true
        
        
            com.alibaba
            druid
            1.1.19
        
        
            mysql
            mysql-connector-java
            runtime
        
        
            com.baomidou
            mybatis-plus-generator
            3.5.1
        
        
            com.baomidou
            mybatis-plus-boot-starter
            3.5.1
        
        
            org.springframework.boot
            spring-boot-starter-data-redis
        
        
            cn.hutool
            hutool-all
            5.7.20
        
    

在recources目录下 创建application springboot的配置文件 分为开发环境和生产环境,两种配置方案,随时切换
application.yml

spring:
  profiles:
    active: dev
  application:
    name: HotelManger
mybatis-plus:
  mapper-locations: classpath:/com/yan/*.xml
  type-aliases-package: com.yan.entity

application-dev.yml

server:
  port: 8888
spring:
  datasource:
    username: root
    password: 1234
    type: com.alibaba.druid.pool.DruidDataSource
    url: jdbc:mysql://localhost:3306/hotelsys?serverTimezone=Asia/Shanghai&zeroDateTimeBehavior=convertToNull&autoReconnect=true&useSSL=false&failOverReadOnly=false
    driver-class-name: com.mysql.cj.jdbc.Driver
  redis:
    host: 192.168.83.100
    port: 6380
    database: 1
logging:
  level:
    com.yan.mapper: debug
#    root: warn
isStartRedis: 0

application-prod.yml 放入部署时的配置

创建启动类

@SpringBootApplication
public class HotelMangerApplication {
    public static void main(String[] args) {
        SpringApplication.run(HotelMangerApplication.class,args);
    }
}

按照数据库表,建立对应实体类,以及统一返回给前端格式的类

package com.yan.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.experimental.Accessors;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Accessors(chain = true)
public class Common{
    private Integer status;
    private String msg;
    private Object data;
   public static Common error(int status,String msg){
        return new Common(status,msg,null);
    }
    public static Common success(String msg,Object data){
       return new Common(200,msg,data);
    }
    public static Common success(String msg){
        return new Common(200,msg,null);
    }
}

创建mapper层,service层,control层,根据需要,如果是多表查询,mybatisplus需要使用mapper.xml文件

例如 customerMapper.xml 在查询顾客时,还要展现对应的等级,等级在另一张表 涉及多表查询



      
    
       
        
        
        
        
        
           
            
            
        
    


    SELECT * FROM `customer` c,grade g WHERe c.grade=g.gradeid

    
    SELECT * FROM `customer` c,grade g WHERe c.grade=g.gradeid

查询在住顾客

    @GetMapping("getInAll")
    public Common getNoAllCus()

通过用户表iddel字段实现,该字段开始为了实现假删除设计,后来觉得用来判断是否在住更加合适 即用户是否有效 在开房时,通过用户cid将此字段修改为0 退房时,通过用户cid将此字段修改为1
底层

mapper.selectList(new QueryWrapper().eq("isdel",0));

根据身份证号 或 顾客电话号 查询

 @GetMapping("getByTel/{tel}")
    public Common getCusByTel(@PathVariable Long tel)

@GetMapping("getById/{id}")
    public Common getCusById(@PathVariable Long id)

两者只有字段不同 用相同底层实现,通过service层 封装 getCusByParam(String param,Long val)
调用dao层 mapper.selectOne(new QueryWrapper().eq(param,val));

注册员工

 @PostMapping("regCus")
    public Common regCus(@RequestBody Customer customer)

前端传递对象 dao层使用mapper.insert(customer);

更新顾客信息

 @PostMapping("update")
    public Common updateCus(@RequestBody Customer customer)

当前端实现注册会员时候 也是修改顾客信息 dao层使用mapper.update(customer,new QueryWrapper().eq("cid",customer.getCid())

房间模块 RoomController

查询房间所有信息

 @GetMapping("/getAll")
    public Common getAllRoom()

使用多表查询 连接roomtype表

package com.yan.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
@TableName("room")
public class Room {
    @TableId
    private Integer rid;
    private Integer rtype;
    private Double extraprice;
    private Integer status;
    private String comment;
    @TableField(exist = false)
    private RoomType roomtype;
}

mapper映射




    
        
        
        
        
        
        
            
            
            
            
        
    

  
        SELECT r.rid ,r.rtype,r.extraprice,r.`status`,r.`comment`,t.typename ,t.`describe` ,t.standardprice,t.tid
        from room r , roomtype t
        WHERe r.rtype=t.tid
          and r.`status`=#{status}
    
 public List getAllFullRoom() {
        return mapper.getRoomByParam(1);
    }

    public List getAllRemainRoom() {

        return mapper.getRoomByParam(0);
    }

    public List getAllStopRoom() {
        return mapper.getRoomByParam(2);
    }

**添加房间 **

 @PostMapping("/addRoom")
    public Common addRoom(@RequestBody Room room)

前传递对象 底层一句mapper.insert(room);

更新房间

@PostMapping("/updateRoom")
    public Common updateRoom(@RequestBody Room room)
  mapper.update(room,new QueryWrapper<>().
  eq("rid",room.getRid);

删除房间

@DeleteMapping("/{rid}")
    public Common delRoom(@PathVariable("rid") int rid)

前端以restful形式传递房间号 底层调用

mapper.delete(new QueryWrapper().eq("rid",rid)
订单模块 OrderController

创建订单(开房操作)

@PostMapping("/create")
    public Common createOrder(@RequestBody Map map)

前端传递对象,对象的属性 后端用map作为key接收(也可以用order接收)

创建一个order对象 order
利用hutool工具包 获取一个唯一标识id 并设置为order的id,将订单的状态设置为未完成(因为开房,订单为进行时 退房时 为完成时 ) 从前台获取业务员的eid,房间号rid,顾客身份号cid 并设置 。获取房间使用时长,根据rid从数据中查询对象,判断房间状态 判断类型,由此确定时长为天数还是小时数 和对应价钱(房间类型标准价钱±每个房间的浮动) ,根据顾客身份号获取顾客对象 将开房人的状态设置为0 获取顾客等级由此知道顾客享受的折扣 ,最终价钱=(房间类型标准价钱±每个房间的浮动)*折扣 。
获取系统日期为startTime 如果房间类型为钟点房 利用hutool 在现在时间加上对应小时数的时间 转为string 进行设置 ;如果为普通间 再次基础上加上天数,将日期去掉时间,加上当天12:00 确保不管几点入住 截止时间为对应天数第二天12点退房 。其余获取备注,同住人cid 最后对订单对象进行插入保存。加上事务 ,使得过程出错,数据得以回滚。

 public Common createOrder(Map map) {
        try {
            System.out.println(map.toString());
            MyOrder order = new MyOrder();
            // oid
            order.setOid( IdUtil.fastSimpleUUID());
            // status
            order.setStatus(1);
            // 必要的key

            String session1 = map.get("key").toString().substring(4);
            System.out.println(session1);

            // 停掉redis 测试


            Employee employee = (Employee) eMapper.getEmsById(Integer.parseInt(session1)).getData();
//            Employee employee = (Employee) redisTemplate.opsForValue().get(session);
            // eid
            order.setEid(employee.getEid());
            // 原计划 直接前端传入间隔
            Integer daysOrHours = Integer.parseInt(String.valueOf(map.get("daysOrHours"))) ;
            // 现在前端传入截止日期



            Integer rid =Integer.parseInt(String.valueOf(map.get("rid"))) ;
            // rid
            order.setRid(rid);
            Room room = rService.getRoomByRid(rid);
            if(room.getStatus()!=0){
                return  Common.error(500,"该房间不可预订");
            }

            // realprice
            Double extraprice = room.getExtraprice();
            RoomType roomtype = room.getRoomtype();
            Double standardprice = roomtype.getStandardprice();

            
           String cid =String.valueOf(map.get("cid"));
            long l = Long.parseLong(cid);
            //cid
            order.setCid(l);

          Common cus = cService.getCusByParam("cid", l);

            Customer customer = (Customer) cus.getData();
            customer.setIsdel(1);
            double dis= customer.getGrade1().getDiscount();

            Double realprice=(standardprice+extraprice)*dis;

            DecimalFormat df = new DecimalFormat("0.00");
            String format = df.format(realprice);
            double v = Double.parseDouble(format);
            order.setRealprice(v);
            String now = DateUtil.now();
            order.setStarttime(now);

            // date
            if(room.getRtype()==6){
                // 假设 钟点房 时长 最低1h  最高 6h 任意时间入住
                Date dateNow= DateUtil.parse(now);
                DateTime dateTime = DateUtil.offsetHour(dateNow, daysOrHours);
                order.setEndtime(dateTime.toString());
            }else {
                // 假设一次最多14天 一律中午12点前退房
                Date dateNow= DateUtil.parse(now);
                DateTime dateTime = DateUtil.offsetDay(dateNow, daysOrHours);
                Date parse = DateUtil.parse(dateTime.toString("yyyy-MM-dd"));
                DateTime endtime = DateUtil.offsetHour(parse, 12);
                order.setEndtime(endtime.toString());
            }
            //可选操作
            // remark
            Object remark = map.get("remark");
            if(!ObjectUtil.isNull(remark)){
                order.setRemark(remark.toString());
            }
            // cidrest
            Object cidrest = map.get("cidrest");
            if (!ObjectUtil.isNull(cidrest)) {
                order.setCrest((List) cidrest);
            }
            System.out.println(order);
            int insert = oMapper.createOrder(order);

            if(insert==1){
                room.setStatus(1);
                rMapper.updateRoom(room);
                cService.updateCus(customer);

                return Common.success("订单创建成功",order);
            }
            return Common.error(500,"出错");
        }
        catch (Exception e){
            return Common.error(500,"出错");
        }
    }

退房操作(获取订单,修改状态后保存)

@GetMapping("/finish/{rid}/{cid}")
    public Common finishOrder(@PathVariable("rid") int rid,@PathVariable("cid") Long cid){
        return service.finishOrder(rid,cid);
    }

前端传递房间号和开房人身份证号查找唯一订单(因为在开房时设置 每个用户只能开一个房间,也可以根据订单号作为凭证,开房时返回给用户,用户由此退房),检测订单状态 防止重复退房 在对订单状态设置为已完成(1) 将房间状态进行修改 ,对用户是否在住进行修改 获取当前系统时间作为最终离开时间 并与截止时间都转为时间对象再咋转为 毫秒数进行比较,如果离开时间大于截止时间,判定为超时,并将大于的毫秒数转为小时数 对订单备注进行设置 最后update 进行更新 同样如果出错,进行数据回滚

 public Common finishOrder(int rid, Long cid) {
        try {
            Common orderByCR = getOrderByCR(rid, cid);
            MyOrder data = (MyOrder) orderByCR.getData();
            if(data.getStatus().equals(1)){
                return Common.error(500,"订单已完成");
            }
            // 订单失效
            data.setStatus(0);
            String now = DateUtil.now();
            data.setRealtime(now);

            // 如果退房超时 给出提示 打在订单上
            Date dateNow= DateUtil.parse(now);
            String endtime = data.getEndtime();
            Date dateend= DateUtil.parse(endtime);
            if(dateNow.getTime()>dateend.getTime()){
              Long  overtime=dateNow.getTime()-dateend.getTime();

                long overHours = TimeUnit.MILLISECONDS.toHours(overtime);
                data.setRemark("超时 "+overHours+"小时");
            }
            // 房间
            Room roomByRid = rService.getRoomByRid(data.getRid());
            if(roomByRid.getStatus().equals(0)){
                return Common.error(500,"房间号错误");
            }
            roomByRid.setStatus(0);
            // 顾客
            Common cus = cService.getCusByParam("cid", cid);
            Customer data1 = (Customer) cus.getData();
            data1.setIsdel(0);
            cService.updateCus(data1);
            rService.updateRoom(roomByRid);
            updateOrder(data);
            return Common.success("退房成功",data);
        }
        catch (Exception e){
            return Common.error(500,"系统错误");
        }
    }

按条件查询订单

  @GetMapping("/getAllByCid/{cid}")
      public Common getAllOrderByCid(Long cid)
 oMapper.selectList(new QueryWrapper().eq("cid", cid));

查询正在进行订单和已完成订单

 @GetMapping("/getRunOrder")
    public Common getRunOrder(){
        return service.getRunOrder(1);
    }
  @GetMapping("/getFinOrder")
    public Common getFinOrder()

oMapper.selectList(new QueryWrapper().eq("status",i)));

后端部分完成

后端有待改进

缺少安全保护,数据库密码用明文存储 ,后续将使用shiro技术
对接口的保护全靠前端,接口暴露,后续在后端设置拦截器 利用jwt判断身份拦截

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/952716.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号