You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

44 KiB

酒店管理系统开发文档

一、技术栈

1.数据库mysql5.7

2.jdk1.8

3.maven+gitee管理项目

4.后台模板layuimini+ssm框架

二、数据库设计

1.部门表

image-20220416135554136

2.员工表

image-20220416135538343

三、环境搭建

1.配置spring

2.配置springMvc

3.配置mybatis

4.配置数据源

四、项目开发

1.相关资料导入

导入layuimini相关代码我们把所有关于后台数据都放入到WEB-INF文件夹下面 但是我们直接访问是访问不了的 所有我们在控制层写一个方法进入到该文件夹

因为是后台 所以我们文件都放入到admin文件夹下面

//专门用来控制 负责跳转后台页面的
@Controller
@RequestMapping("/admin")
public class SystemController {
    //去到登录页面
    @RequestMapping("/login.html")
    public String login(){
        return "login";
    }
}

2.实现用户登录功能

1编写实体类

private Integer id;
private String username;
private String password;
private String name;
private String sex;
private Integer deptId;
private Date hireDate;//入职时间
private String salt;//密码加密值
private Date createDate;
private Integer createBy;
private Integer modifyBy;//修改人
private Date modifyDate;
private String remark;//备注

2编写mapper相关接口

public Employee findNameLogin(String username);//按用户名查询

3编写mapper接口mysql语句

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="comxyp.mapper.EmployeeMapper">
    <!--根据用户名查询员工信息-->
    <select id="findNameLogin" resultType="comxyp.pojo.Employee">
        select * from employee_table where username = #{username}
    </select>
</mapper>

4编写service接口方法

//用户登录
public Employee userLogin(String username,String password);

5实现service接口方法

@Service
public class EmployeeServiceImpl implements EmployeeService {
    @Autowired
    private EmployeeMapper employeeMapper;
    @Override
    //用户登录
    public Employee userLogin(String username,String password) {
        Employee employee = employeeMapper.findNameLogin(username);
            if(employee!=null){
                //与用户输入密码进行比较
                if(employee.getPassword().equals(password)){//登录成功
                    return employee;
                }
            }
        return  null;
    }
}

6编写controller实现

@Controller
@RequestMapping("/employee")
public class EmployeeController {
    @Autowired
    private EmployeeService employeeService;
    @RequestMapping("/login")
    @ResponseBody
    public String login(String username, String password,String code, HttpSession session){
        System.out.println(username);
        System.out.println(password);
        Map<String,Object> map = new HashMap<>();
        Employee employee = employeeService.userLogin(username,password);
        if(employee!=null){
            //保存用户登录信息
            session.setAttribute("user",employee);
            map.put("success",true);
        } else if(employee==null){
            map.put("success",false);
            map.put("msg","用户名或者密码错误");
        } else if(!code.equals("xSzG")){
            map.put("msg","验证码错误");
         }
        return JSON.toJSONString(map);
    }
}

7修改login.jsp页面相关代码

<div class="layui-container">
    <div class="admin-login-background">
        <div class="layui-form login-form">
            <form class="layui-form" action="">
                <div class="layui-form-item logo-title">
                    <h1>酒店后台管理登录</h1>
                </div>
                <div class="layui-form-item">
                    <label class="layui-icon layui-icon-username" for="username"></label>
                    <input type="text" name="username" id="username" lay-verify="required|account" placeholder="用户名或者邮箱" autocomplete="off" class="layui-input" value="xyp">
                </div>
                <div class="layui-form-item">
                    <label class="layui-icon layui-icon-password" for="password"></label>
                    <input type="password" name="password" id="password" lay-verify="required|password" placeholder="密码" autocomplete="off" class="layui-input" value="123">
                </div>
                <div class="layui-form-item">
                    <label class="layui-icon layui-icon-vercode"></label>
                    <input type="text" name="code" lay-verify="required|captcha" placeholder="图形验证码" autocomplete="off" class="layui-input verification captcha" value="xSzG">
                    <div class="captcha-img">
                        <img id="captchaPic" src="${pageContext.request.contextPath}/static/layui/images/captcha.jpg">
                    </div>
                </div>
                <div class="layui-form-item">
                    <input type="checkbox" name="rememberMe" value="true" lay-skin="primary" title="记住密码">
                </div>
                <div class="layui-form-item">
                    <button class="layui-btn layui-btn layui-btn-normal layui-btn-fluid" lay-submit="" lay-filter="login">登 入</button>
                </div>
            </form>
        </div>
    </div>
</div>
<script src="${pageContext.request.contextPath}/static/layui/lib/jquery-3.4.1/jquery-3.4.1.min.js" charset="utf-8"></script>
<script src="${pageContext.request.contextPath}/static/layui/lib/layui-v2.6.3/layui.js" charset="utf-8"></script>
<script src="${pageContext.request.contextPath}/static/layui/lib/jq-module/jquery.particleground.min.js" charset="utf-8"></script>
<script>
    layui.use(['form','layer','jquery'], function () {
        var form = layui.form,
            layer = layui.layer;
           $=layui.jquery;

        // 登录过期的时候跳出ifram框架
        if (top.location != self.location) top.location = self.location;

        // 粒子线条背景
        $(document).ready(function(){
            $('.layui-container').particleground({
                dotColor:'#7ec7fd',
                lineColor:'#7ec7fd'
            });
        });

        // 进行登录操作
        form.on('submit(login)', function (data) {
           //可以获取到表单中所有数据 data = data.field;
            //发送登录请求
            $.post("${pageContext.request.contextPath}/employee/login",data.field,function (result) {
               // console.log(result);
                if(result.success){//如果登录成功跳转到后台页面
                    location.href="home.html";
                } else{//登录失败 提示用户
                    layer.msg(result.msg);
                }
            },"json");
            return false;
        });
    });
</script>
</body>

8浏览器乱码问题解决

当我们把java对象转换为json格式返回到浏览器上时 可能会错写乱码问题 所以我们此时去springMVC中进行配置

第一步把java对象转换为JSON格式 我们要导入相应的坐标

<!--Fastjson 是一个 Java 库,可以将 Java 对象转换为 JSON 格式,
  当然它也可以将 JSON 字符串转换为 Java 对象。.-->
<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>fastjson</artifactId>
  <version>1.2.73</version>
</dependency>

第二步:在配置

<!--配置mvc注解驱动-->
<!--能支持springmvc更高级的一些功能 JSR303校验  ajax等-->
<mvc:annotation-driven>
    <mvc:message-converters>
        <!--@ResponseBody 中文响应乱码 -->
        <bean class="org.springframework.http.converter.StringHttpMessageConverter">
            <property name="supportedMediaTypes">
                <list>
                    <value>
                        text/plain;charset=UTF-8
                    </value>
                    <value>
                        text/html;charset=UTF-8
                    </value>

                    <value>
                        application/json;charset=UTF-8
                    </value>
                    <value>
                        application/x-www-form-urlencoded;charset=UTF-8
                    </value>
                </list>
            </property>
        </bean>


        <!-- JSON中文请求乱码及解决
        HttpMediaTypeNotAcceptableException: Could not find acceptable representation  异常信息-->
        <bean id="jacksonMessageConverter"
              class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
            <property name="supportedMediaTypes">
                <list>
                    <value>
                        application/json;charset=UTF-8
                    </value>
                    <value>
                        application/x-www-form-urlencoded;charset=UTF-8
                    </value>
                </list>
            </property>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

3.实现注册功能

1编写mapper相关接口

//保存用户信息
public int saveUser(Employee employee);

2表现实现mapper接口Mysql语句

 <!--保存用户-->
<insert id="saveUser" parameterType="comxyp.pojo.Employee">
    insert into employee_table(id,username,password,name,sex,deptId,hireDate)
    values (#{id},#{username},#{password},#{name},#{sex},#{deptId},#{hireDate})
</insert>

3编写service接口方法

//保存用户
public int saveUser(Employee employee);

4实现service接口方法

public int saveUser(Employee employee) {
    return employeeMapper.saveUser(employee);
}

5编写controller实现

@RequestMapping("/register")
@ResponseBody
public String register( String username,  String password, String names, String sex,Integer depId){
    Map<String,Object> map = new HashMap<>();
    Employee employees = new Employee();
    employees.setId(null);
    employees.setUsername(username);
    employees.setPassword(password);
    employees.setName(names);
    employees.setSex(sex);
    employees.setDeptId(depId);
    employees.setHireDate(new Date());
    Employee employee = employeeService.userLogin(username,password);
    int n  = employeeService.saveUser(employees);
    if(employee!=null){
            //保存用户登录信息
        //用户名已经存在
        map.put("success", false);
        map.put("msg", "用户名已经存在");
    } else{
        if(n>0){
            map.put("success", true);
            map.put("msg","注册成功");
        }
    }
    return JSON.toJSONString(map);
}

6修改registe.jsp页面相关代码

<div class="layui-container">
    <div class="admin-login-background">
        <div class="layui-form login-form">
            <form class="layui-form" action="" id="update_frm">
                <div class="layui-form-item logo-title">
                    <h1>酒店后台管理注册</h1>
                </div>
                <div class="layui-form-item">
                    <label class="layui-icon layui-icon-username" for="username"></label>
                    <input type="text" name="username" id="username" lay-verify="required|account" placeholder="用户名或者邮箱" autocomplete="off" class="layui-input" value="">
                </div>
                <div class="layui-form-item">
                    <label class="layui-icon layui-icon-password" for="username"></label>
                    <input type="password" name="password"  lay-verify="required|password" placeholder="密码" autocomplete="off" class="layui-input" value="">
                </div>
                <div class="layui-form-item">
                    <label class="layui-icon layui-icon-password" ></label>
                    <input type="text" name="names"  lay-verify="required|account" placeholder="姓名" autocomplete="off" class="layui-input" value="">
                </div>
                <div class="layui-form-item">
                    <input type="text" name="text" maxlength="2"  lay-verify="required|account" placeholder="性别" autocomplete="off" class="layui-input" value="">
                </div>
                <div class="layui-form-item">
                    <label class="layui-icon layui-icon-password" ></label>
                    <input type="text" name="depId" id="depId" lay-verify="required|account" placeholder="部门编号" autocomplete="off" class="layui-input" value="">
                </div>

                <div class="layui-form-item">
                   <a href="${pageContext.request.contextPath}/admin/login.html">已有账号?返回登录</a>
                </div>
                <div class="layui-form-item">
                    <button class="layui-btn layui-btn layui-btn-normal layui-btn-fluid" lay-submit="" lay-filter="login">注册</button>
                </div>
            </form>
        </div>
    </div>
</div>
<script src="${pageContext.request.contextPath}/static/layui/lib/jquery-3.4.1/jquery-3.4.1.min.js" charset="utf-8"></script>
<script src="${pageContext.request.contextPath}/static/layui/lib/layui-v2.6.3/layui.js" charset="utf-8"></script>
<script src="${pageContext.request.contextPath}/static/layui/lib/jq-module/jquery.particleground.min.js" charset="utf-8"></script>
<script>
    layui.use(['form','layer','jquery'], function () {
        var form = layui.form,
            layer = layui.layer,
           $=layui.jquery;

        // 登录过期的时候跳出ifram框架
        if (top.location != self.location) top.location = self.location;

        // 进行登录操作
        form.on('submit(login)', function (data) {
            //可以获取到表单中所有数据 data = data.field;
            //发送登录请求
            $.post("${pageContext.request.contextPath}/employee/register",data.field,function (result) {
                console.log(result);
                if(result.success){//如果登录成功跳转到后台页面
                    location.href="${pageContext.request.contextPath}/admin/login.html";
                } else{//登录失败 提示用户
                    layer.msg(result.msg);
                }
            },"json");
            return false;
        });
    });
</script>
</body>

4.实现首页功能

1修改首页的相关内容

导入layuimini的index.html页面进行修改

2退出登录

在控制层编写访问退出登录访问路径

//退出登录
@RequestMapping("/logout.html")
public String logout(HttpSession session){
    //清空session
    session.removeAttribute("user");
    return "redirect:/admin/login.html";
}
<dd>
    <a href="javascript:;" class="login-out">退出登录</a>
</dd>
$('.login-out').on("click", function () {
    layer.confirm('确定要退出吗?', {icon: 3, title:'提示'}, function(index){
        location.href="${pageContext.request.contextPath}/admin/logout.html"
        layer.close(index);
    });
});

3使用拦截器 拦截除登录页面之外的其他页面

拦截器拦截是放在WEB-INF下面页面

为了安全 我们只有登录成功之后 才能访问其他页面 所以 我们使用拦截器

第一步:编写拦截器方法:

public class LoginInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //判断session是否为空
        if((request.getSession().getAttribute("user")==null)){
            //如果没有登录,则去到登录页面
            response.sendRedirect(request.getContextPath()+"/admin/login.html");
            return false;//验证失败,进行拦截
        }
        //验证通过
        return true;
    }
}

第二步去springMvc中进行拦截器配置

<!--拦截器配置-->
<mvc:interceptors>
    <mvc:interceptor>
        <!--拦截所有以/admin/开头的访问路径-->
        <mvc:mapping path="/admin/**"></mvc:mapping>
        <!--排除员工登录的访问路径-->
        <mvc:exclude-mapping path="/admin/employee/login"/>
        <mvc:exclude-mapping path="/admin/login.html"/>
        <!--注入拦截-->
        <bean class="comxyp.interceptor.LoginInterceptor"></bean>
    </mvc:interceptor>
</mvc:interceptors>

4过滤器使用

如果我们要拦截在webapp下面页面 我们使用过滤器 如果没有登录 是不可以访问后台页面的

所以第一步我们新建一个过滤器类:

//自定义过滤器
public class LoginFilter implements Filter {
    //初始化方法
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        //初始化处理
        System.out.println("过滤器初始化");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request= (HttpServletRequest) servletRequest;
        HttpServletResponse response= (HttpServletResponse) servletResponse;
        HttpSession session=request.getSession();
        if(session.getAttribute("user")==null){
            //非法请求,直接跳转到登陆界面
            //如果没有登录,则去到登录页面
            response.sendRedirect(request.getContextPath()+"/admin/login.html");
        }else{
            //正常登录,放行
            filterChain.doFilter(request,response);
        }
    }

    @Override
    public void destroy() {
        //释放资源
        System.out.println("过滤器销毁");
    }
}

第二步去web.xml中进行过滤器配置

<!--使用过滤器实现登陆控制-->
<!--filter标签用于声明过滤器对象-->
<filter>
  <!--过滤器名称-->
  <filter-name>LoginFilter</filter-name>
  <!--过滤器完整类名-->
  <filter-class>comxyp.filter.LoginFilter</filter-class>
</filter>
<!--filter-mapping用于创建过滤器的映射指定Web应用中哪些URL应用哪一个过滤器进行处理-->
<filter-mapping>
  <filter-name>LoginFilter</filter-name>
  <!--url-pattern用于指定过滤器应用的URL-->
  <!--过滤的页面(自定义),这里对登录界面就不要过滤了-->
  <url-pattern>/jsp/*</url-pattern>
</filter-mapping>

5.菜单设计

1菜单表设计 参照layuimini开发手册

CREATE TABLE `system_menu` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `pid` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '父ID',
  `title` varchar(100) NOT NULL DEFAULT '' COMMENT '名称',
  `icon` varchar(100) NOT NULL DEFAULT '' COMMENT '菜单图标',
  `href` varchar(100) NOT NULL DEFAULT '' COMMENT '链接',
  `target` varchar(20) NOT NULL DEFAULT '_self' COMMENT '链接打开方式',
  `sort` int(11) DEFAULT '0' COMMENT '菜单排序',
  `status` tinyint(1) unsigned NOT NULL DEFAULT '1' COMMENT '状态(0:禁用,1:启用)',
  `remark` varchar(255) DEFAULT NULL COMMENT '备注信息',
  `create_at` timestamp NULL DEFAULT NULL COMMENT '创建时间',
  `update_at` timestamp NULL DEFAULT NULL COMMENT '更新时间',
  `delete_at` timestamp NULL DEFAULT NULL COMMENT '删除时间',
  PRIMARY KEY (`id`),
  KEY `title` (`title`),
  KEY `href` (`href`)
) ENGINE=InnoDB AUTO_INCREMENT=250 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='系统菜单表';

2参照java示列 java动态生成初始化数据spring框架

设计数据库:

image-20220416135502349

3编写菜单实体类

private Integer id;
private Integer pid;
private String title;
private String href;
private Integer spread;
private String target;
private String icon;

4编写mapper接口

List<Menu> findAll();//查询所有菜单列表

5编写mapper.xml对应相关mysql语句

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="comxyp.mapper.MenuMapper">
    <!--查询所有菜单列表-->
    <select id="findAll" resultType="comxyp.pojo.Menu">
        select * from sys_menu;
    </select>

</mapper>

6编写service层接口

List<Menu> findAll();//查询所有菜单列表

7实现service层接口

@Service
public class MenuServiceImpl implements MenuService {
    @Autowired
    private MenuMapper mapper;
    @Override
    public List<Menu> findAll() {
        return mapper.findAll();
    }

8编写controller功能

分析原来我们使用加载菜单信息是api中init.json中数据 现在我们用数据库显示构建出来;

{
  "homeInfo": {
    "title": "首页",
    "href": "${pageContext.request.contextPath}/static/layui/page/welcome-1.html?t=1"
  },
  "logoInfo": {
    "title": "LAYUI MINI",
    "image": "${pageContext.request.contextPath}/static/layui/images/logo.png",
    "href": ""
  },
  "menuInfo": [
    {
      "title": "常规管理",
      "icon": "fa fa-address-book",
      "href": "",
      "target": "_self",
      "child": [
        {
          "title": "主页模板",
          "href": "",
          "icon": "fa fa-home",
          "target": "_self",
          "child": [
            {
              "title": "主页一",
              "href": "page/welcome-1.html",
              "icon": "fa fa-tachometer",
              "target": "_self"
            },
            {
              "title": "主页二",
              "href": "page/welcome-2.html",
              "icon": "fa fa-tachometer",
              "target": "_self"
            },
            {
              "title": "主页三",
              "href": "page/welcome-3.html",
              "icon": "fa fa-tachometer",
              "target": "_self"
            }
          ]
        },
        {
          "title": "菜单管理",
          "href": "page/menu.html",
          "icon": "fa fa-window-maximize",
          "target": "_self"
        },
        {
          "title": "系统设置",
          "href": "page/setting.html",
          "icon": "fa fa-gears",
          "target": "_self"
        },
        {
          "title": "表格示例",
          "href": "page/table.html",
          "icon": "fa fa-file-text",
          "target": "_self"
        },
        {
          "title": "表单示例",
          "href": "",
          "icon": "fa fa-calendar",
          "target": "_self",
          "child": [
            {
              "title": "普通表单",
              "href": "page/form.html",
              "icon": "fa fa-list-alt",
              "target": "_self"
            },
            {
              "title": "分步表单",
              "href": "page/form-step.html",
              "icon": "fa fa-navicon",
              "target": "_self"
            }
          ]
        },
        {
          "title": "登录模板",
          "href": "",
          "icon": "fa fa-flag-o",
          "target": "_self",
          "child": [
            {
              "title": "登录-1",
              "href": "page/login-1.html",
              "icon": "fa fa-stumbleupon-circle",
              "target": "_blank"
            },
            {
              "title": "登录-2",
              "href": "page/login-2.html",
              "icon": "fa fa-viacoin",
              "target": "_blank"
            },
            {
              "title": "登录-3",
              "href": "page/login-3.html",
              "icon": "fa fa-tags",
              "target": "_blank"
            }
          ]
        },
        {
          "title": "异常页面",
          "href": "",
          "icon": "fa fa-home",
          "target": "_self",
          "child": [
            {
              "title": "404页面",
              "href": "page/404.html",
              "icon": "fa fa-hourglass-end",
              "target": "_self"
            }
          ]
        },
        {
          "title": "其它界面",
          "href": "",
          "icon": "fa fa-snowflake-o",
          "target": "",
          "child": [
            {
              "title": "按钮示例",
              "href": "page/button.html",
              "icon": "fa fa-snowflake-o",
              "target": "_self"
            },
            {
              "title": "弹出层",
              "href": "page/layer.html",
              "icon": "fa fa-shield",
              "target": "_self"
            }
          ]
        }
      ]
    },
    {
      "title": "组件管理",
      "icon": "fa fa-lemon-o",
      "href": "",
      "target": "_self",
      "child": [
        {
          "title": "图标列表",
          "href": "page/icon.html",
          "icon": "fa fa-dot-circle-o",
          "target": "_self"
        },
        {
          "title": "图标选择",
          "href": "page/icon-picker.html",
          "icon": "fa fa-adn",
          "target": "_self"
        },
        {
          "title": "颜色选择",
          "href": "page/color-select.html",
          "icon": "fa fa-dashboard",
          "target": "_self"
        },
        {
          "title": "下拉选择",
          "href": "page/table-select.html",
          "icon": "fa fa-angle-double-down",
          "target": "_self"
        },
        {
          "title": "文件上传",
          "href": "page/upload.html",
          "icon": "fa fa-arrow-up",
          "target": "_self"
        },
        {
          "title": "富文本编辑器",
          "href": "page/editor.html",
          "icon": "fa fa-edit",
          "target": "_self"
        },
        {
          "title": "省市县区选择器",
          "href": "page/area.html",
          "icon": "fa fa-rocket",
          "target": "_self"
        }
      ]
    },
    {
      "title": "其它管理",
      "icon": "fa fa-slideshare",
      "href": "",
      "target": "_self",
      "child": [
        {
          "title": "多级菜单",
          "href": "",
          "icon": "fa fa-meetup",
          "target": "",
          "child": [
            {
              "title": "按钮1",
              "href": "page/button.html?v=1",
              "icon": "fa fa-calendar",
              "target": "_self",
              "child": [
                {
                  "title": "按钮2",
                  "href": "page/button.html?v=2",
                  "icon": "fa fa-snowflake-o",
                  "target": "_self",
                  "child": [
                    {
                      "title": "按钮3",
                      "href": "page/button.html?v=3",
                      "icon": "fa fa-snowflake-o",
                      "target": "_self"
                    },
                    {
                      "title": "表单4",
                      "href": "page/form.html?v=1",
                      "icon": "fa fa-calendar",
                      "target": "_self"
                    }
                  ]
                }
              ]
            }
          ]
        },
        {
          "title": "失效菜单",
          "href": "page/error.html",
          "icon": "fa fa-superpowers",
          "target": "_self"
        }
      ]
    }
  ]
}

第一步:我们需要编写一个菜单节点的工具类 里面放置的是子菜单的信息:

private Integer id;//菜单编号
private Integer pid;//父级菜单编号
private String title;//菜单名称
private String href;//链接地址
private Integer spread;//是否展开
private String target;//打开方式
private String icon;//图标
private List<MenuNode> child;//子菜单集合列表

第二步 编写controller层

@Controller
@RequestMapping("/admin/menu")
public class MenuController {
    @Autowired
    private MenuService menuService;
    //加载首页左侧菜单栏  对应着api接口中init.json中的格式
    @RequestMapping("/loadMenuList")
    @ResponseBody
    public String loadMenuList(){
        //创建map集合保存菜单信息
        Map<String,Object> map = new LinkedHashMap<>();
        //创建map集合保存 homeInfo信息
        Map<String,Object> homeInfo = new LinkedHashMap<>();
        //创建map集合保存 logoInfo信息
        Map<String,Object> logoInfo = new LinkedHashMap<>();
        //查询所有菜单
        List<Menu> list = menuService.findAll();
        //创建集合保存菜单关系
        List<MenuNode> menuNodeList = new ArrayList<>();
        //循环遍历菜单列表  目的是创建菜单之间的层级关系
        for(Menu m:list){
            //创建菜单节点对象
            MenuNode menuNode = new MenuNode();
            menuNode.setHref(m.getHref());//链接地址
            menuNode.setIcon(m.getIcon());//菜单图标
            menuNode.setId(m.getId());//菜单编号
            menuNode.setPid(m.getPid());//父级编号
            menuNode.setSpread(m.getSpread());//是否展开
            menuNode.setTitle(m.getTitle());//菜单标题
            menuNode.setTarget(m.getTarget());//打开方式
            //将对象添加到集合中
            menuNodeList.add(menuNode);
        }

        //保存homeInfo中信息
        homeInfo.put("title","首页");
        homeInfo.put("href","/admin/home.jsp");

        //保存logoInfo 中信息
        logoInfo.put("title","酒店管理系统");//系统标题
        logoInfo.put("image","/static/layui/images/logo.png");//logo图标
        logoInfo.put("href","/admin/home.html");//首页地址

        //将菜单信息添加到MenuInfo集合中
        map.put("menuInfo", TreeUtil.toTree(menuNodeList,0));
        map.put("homeInfo",homeInfo);
        map.put("logoInfo",logoInfo);

        //将信息以json格式返回
        return JSON.toJSONString(map);
    }
}

构建父级菜单与子菜单之间关系 我们使用layuimini给我们提供的一个工具类

//构建菜单层级关系
public class TreeUtil {
    /**
     * 构建菜单层级关系
     * @param treeList      菜单列表
     * @param pid           父级菜单编号0表示父级菜单 (一级菜单)
     * @return
     */
    public static List<MenuNode> toTree(List<MenuNode> treeList, Integer pid) {
        List<MenuNode> retList = new ArrayList<MenuNode>();
        for (MenuNode parent : treeList) {
            //如果当前父级菜单编号与循环的菜单列表中的父级菜单编号一致
            if (pid == parent.getPid()) {
                retList.add(findChildren(parent, treeList));
            }
        }
        return retList;
    }


    private static MenuNode findChildren(MenuNode parent, List<MenuNode> treeList) {
        for (MenuNode child : treeList) {
            if (parent.getId() == child.getPid()) {
                if (parent.getChild() == null) {
                    parent.setChild(new ArrayList<MenuNode>());
                }
                parent.getChild().add(findChildren(child, treeList));
            }
        }
        return parent;
    }
}

9去首页修改端口默认地址

iniUrl: "${pageContext.request.contextPath}/admin/menu/loadMenuList",    // 初始化接口

6.实现部门管理功能

1设计数据库

image-20220416140303824

2修改部门管理页面

我们使用layuimini中table.html页面

3去controller中写好访问管理页面地址

//进入部门管理页面
@RequestMapping("/ToDeptManage")
public String ToDeptManage(){
    return "dept/deptManage";
}

4编写部门管理实体类

private Integer id;
private String deptName;
private String address;
private Date createtime;
private String remark;

因为我们要实现分页显示 所以我们单独写一个分页类 对哪一个分页 就继承谁:

//实现分页
public class Vo extends Dept{
    private Integer page;//当前页码
    private Integer limit;//每页显示数量
4.1导入分页插件坐标
<!--分页插件-->
<dependency>
  <groupId>com.github.pagehelper</groupId>
  <artifactId>pagehelper</artifactId>
  <version>5.0.0</version>
</dependency>
4.2去mybatis中进行配置
<!--分页插件配置-->
<plugins>
    <plugin interceptor="com.github.pagehelper.PageInterceptor">
        <!-- 支持OracleMySQLSQLiteMariaDBHsqldbPostgreSQL -->
        <property name="helperDialect" value="mysql"/>
    </plugin>
</plugins>

5编写mapper接口

//部门相关接口
public interface DeptMapper {
    List<Dept> findAll(Vo vo);
}

6实现mapper接口方法mysql语句

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="comxyp.mapper.DeptMapper">
    <select id="findAll" resultType="comxyp.pojo.Dept">
        select * from dept_table
        <where>
            <if test="deptname!=null and deptname!=''">
                and deptname like concat('%',#{deptname},'%')
            </if>
        </where>
    </select>
</mapper>

7编写service层接口

public interface DeptService {
    List<Dept> findAll(Vo vo);
}

8实现接口

@Service
public class DeptServiceImpl implements DeptService {
    @Autowired
    private DeptMapper deptMapper;
    @Override
    public List<Dept> findAll(Vo vo) {
        return deptMapper.findAll(vo);
    }
}

9编写controller层功能

9.1因为我们使用的是layuimini 所以它要求我们返回数据有要求 提供了一个工具类:
package comxyp.utils;

/**
 * layui 数据表格类
 */
public class DataGridViewResult {
    private Integer code=0;//执行状态码
    private String msg="";//提示信息
    private Long count=0L;//数量
    private Object data;//数据

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Long getCount() {
        return count;
    }

    public void setCount(Long count) {
        this.count = count;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    /**
     * 创建数据表格对象
     * @param count     数据总数量
     * @param data      数据集合列表
     */
    public DataGridViewResult(Long count, Object data) {
        super();
        this.count = count;
        this.data = data;
    }
    public DataGridViewResult(Object data) {
        super();
        this.data = data;
    }

    public DataGridViewResult() {
    }
}
9.2编写controller
//部门管理查询显示
@Controller
@RequestMapping("/dept")
public class DeptController {
    @Autowired
    private DeptService deptService;
    @RequestMapping("/deptList")
    public DataGridViewResult deptList(Vo vo){
        //设置分页信息
        PageHelper.startPage(vo.getPage(),vo.getLimit());
        //调用分页查询的方法
         List<Dept> list = deptService.findAll(vo);
         //创建分页对象
        PageInfo<Dept> pageInfo = new PageInfo<>(list);
        //返回数据
        return new DataGridViewResult(pageInfo.getTotal(),pageInfo.getList());
    }

}

7.部门添加

1修改部门列表页面中添加事件

修改相关代码

 //监听头部工具栏事件
        //toolbar是头部工具栏事件
        //currentTableFilter是表格lay-filter过滤器的值
        table.on("toolbar(currentTableFilter)",function (obj) {
            switch (obj.event) {
                case "add"://添加按钮
                    openAddWindow();//打开添加窗口
                    break;
            }
        });
        var url;//提交地址
        var mainIndex;//打开窗口的索引

        /**
         * 打开添加窗口
         */
        function openAddWindow() {
            mainIndex = layer.open({
                type: 1,//打开类型
                title: "添加部门",//窗口标题
                area: ["800px", "400px"],//窗口宽高
                content: $("#addOrUpdateWindow"),//引用的内容窗口
                success: function () {
                    //清空表单数据
                    $("#dataFrm")[0].reset();
                    //添加的提交请求
                   url = "${pageContext.request.contextPath}/dept/addDept";
                }
            });
        }

        //监听表单提交事件
        form.on("submit(doSubmit)",function (data) {
            $.post(url,data.field,function(result){
                if(result.success){
                    //刷新数据表格
                    tableList.reload();
                    //关闭窗口
                    layer.close(mainIndex);
                }
                //提示信息
                layer.msg(result.msg);
            },"json");
            //禁止页面刷新
            return false;
        });
    });
</script>

2编写mapper接口

//添加部门
int addDept(Dept dept);

3编写mapper.xml中mysql语句

<insert id="addDept" parameterType="comxyp.pojo.Dept">
    insert into dept_table(deptname,address,remark) values (#{deptname},#{address},#{remark})
</insert>

3编写service接口

//添加部门
int addDept(Dept dept);

4实现接口

public int addDept(Dept dept) {
    return deptMapper.addDept(dept);
}

5编写controller功能

@RequestMapping("/addDept")
@ResponseBody
public String addDept(Dept dept){
    Map<String,Object> map = new HashMap<>();
    int n= deptService.addDept(dept);
    if(n>0){
        map.put("success",true);
        map.put("msg","添加成功");
    } else{
        map.put("success", false);
        map.put("msg", "添加失败");
    }
    return JSON.toJSONString(map);
}

8.部门修改

1修改页面

8.1添加隐藏域 为某一条修改
<%-- 隐藏域 --%>
<input type="hidden" name="id">
8.2监听行事件 获取某一行的数据
//监听行工具栏事件
table.on("tool(currentTableFilter)",function (obj) {
    console.log(obj);
    switch (obj.event) {
        case "edit"://编辑按钮
            openUpdateWindow(obj.data);//打开修改窗口
            break;
        case "delete"://删除按钮
            deleteById(obj.data);
            break;
    }
});
8.3打开修改窗口
/**
 * 打开修改窗口
 * @param data  当前行的数据
 */
function openUpdateWindow(data) {
    mainIndex = layer.open({
        type: 1,//打开类型
        title: "修改部门",//窗口标题
        area: ["800px", "400px"],//窗口宽高
        content: $("#addOrUpdateWindow"),//引用的内容窗口
        success: function () {
            //表单数据回显
            form.val("dataFrm",data);//参数1lay-filter值  参数2回显的数据
            //修改的提交请求
            url = "${pageContext.request.contextPath}/dept/updateDept";
        }
    });
}

2编写mapper接口

//部门修改
int updateDept(Dept dept);

3编写mapper.xml中mysql语句

<!--部门修改-->
<update id="updateDept" parameterType="comxyp.pojo.Dept">
    update dept_table
    <set>
        <if test="deptname!=null and deptname!=''">
            deptename = #{deptname},
        </if>
        <if test="address!=null and address!=''">
            address = #{address},
        </if>
        <if test="remark!=null and remark!=''">
            remark = #{remark}
        </if>
    </set>
     where id=#{id}
</update>

3编写service接口

//部门修改
int updateDept(Dept dept);

4实现接口

public int updateDept(Dept dept) {
    return deptMapper.updateDept(dept);
}

5编写controller功能

@RequestMapping("/updateDept")
@ResponseBody
public String updateDept(Dept dept){
    Map<String,Object> map = new HashMap<>();
    int n= deptService.updateDept(dept);
    if(n>0){
        map.put("success",true);
        map.put("msg","添加成功");
    } else{
        map.put("success", false);
        map.put("msg", "添加失败");
    }
    return JSON.toJSONString(map);
}

9.部门删除

在删除之前 我们要判断该部门下是否有员工 所以先进行判断检查

9.1编写员工mapper接口 按员工编号查询
/**
 * 根据部门编号查询员工数量
 * @param deptId
 * @return
 */
int getEmployeeCountByDeptId(Integer deptId);
9.2 编写相关mysql语句和service接口
<select id="getEmployeeCountByDeptId" resultType="int">
    <!-- 根据部门编号查询该部门下的员工数量 -->
     select count(1) from employee_table where deptId = #{deptId}
</select>
  public int getEmployeeCountByDeptId(Integer deptId) {
        return employeeMapper.getEmployeeCountByDeptId(deptId);
    }
}
9.3编写controller层功能
@RequestMapping("/checkDeptHasEmployee")
@ResponseBody
public String checkDeptHasEmployee(Integer id){
    Map<String,Object> map = new HashMap<String,Object>();
    //调用根据部门编号查询员工数量的方法
    if(employeeService.getEmployeeCountByDeptId(id)>0){
        map.put("exist",true);//存在
        map.put("msg","该部门存在员工信息,无法删除");
    }else{
        map.put("exist",false);//不存在
    }
    return JSON.toJSONString(map);
}

1修改页面

/**
 * 删除部门
 * @param data  当前行数据
 */
function deleteById(data) {
    //判断当前部门下是否存在员工
    $.get("${pageContext.request.contextPath}/dept/checkDeptHasEmployee",{"id":data.id},function(result){
        if(result.exist){
            //提示用户无法删除
            layer.msg(result.msg);
        }else{
            //提示用户是否删除该部门
            layer.confirm("确定要删吗", {icon: 3, title:'提示'}, function(index){
                //发送ajax请求进行删除
                $.post("${pageContext.request.contextPath}/dept/deleteById",{"id":data.id},function(result){
                    if(result.success){
                        //刷新数据表格
                        tableIns.reload();
                    }
                    //提示
                    layer.msg(result.msg);
                },"json");

                layer.close(index);
            });
        }
    },"json");
}

2编写mapper接口

//删除
int deleteById(Integer id);

3编写mapper.xml中mysql语句

   <delete id="deleteById">
        delete from dept_table where id=#{id}
    </delete>
</mapper>

3编写service接口

//删除
int deleteById(Integer id);

4实现接口

public int  deleteById(Integer id) {
    return  deptMapper.deleteById(id);
}

5编写controller功能

/**
 * 删除部门
 * @param id
 * @return
 */
@RequestMapping("/deleteById")
@ResponseBody
public String deleteById(Integer id){
    Map<String,Object> map = new HashMap<String,Object>();
    //调用删除部门的方法
    if(deptService.deleteById(id)>0){
        map.put("success",true);//成功
        map.put("msg","删除成功");
    }else{
        map.put("success",false);//失败
        map.put("msg","删除失败");
    }
    return JSON.toJSONString(map);
}