前文推荐
汽车租赁系统的介绍和项目搭建(1)
JavaSSM框架学完,手写一个汽车租赁系统,真NE!
汽车租赁系统(2)-完成登录功能

工作台开发

首先明确工作台的位置

分析工作台开发

  • 分析页面:
    1. 有一个xxx欢迎您,要获取当前登录的用户名,或者系统时间
    2. 最新文章,这里提供一个获取最新文章的控制器接口,之后我们要做系统公告的获取,然后在这里展示
  • 分析后台:
    1. 提供一个从主页index.jsp转跳到工作台的控制器
    2. 修改index.jsp中该位置的控制器地址

1.创建DeskController

是工作台显示的Controller

  • 访问Controller时让其转到我们想要显示的jsp页面
package per.leiyu.sys.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/** * 工作台的控制器 */
@Controller
@RequestMapping("desk")
public class DeskManager {

    /** * 跳转到工作台的页面 */
    @RequestMapping("toDeskManager")
    public String toDeskManager(){
        return "system/main/deskManager";
    }

}

2.创建DeskManger.jsp

工作台的页面

<%--
  Created by IntelliJ IDEA.
  User: LYJ
  Date: 2020年7月7日
  Time: 21:52:14
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <meta charset="utf-8">
    <title>工作台</title>
    <meta name="renderer" content="webkit">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="format-detection" content="telephone=no">
    <link rel="stylesheet" href="${leiyujia}/static/layui/css/layui.css" media="all" />
    <link rel="stylesheet" href="${leiyujia}/static/css/public.css" media="all" />
</head>
<body class="childrenBody">
<blockquote class="layui-elem-quote layui-bg-green">
    <div id="nowTime"></div>
</blockquote>
<div class="layui-row layui-col-space10">
    <div class="layui-col-lg6 layui-col-md6">
        <blockquote class="layui-elem-quote title">最新文章 <i class="layui-icon layui-red">&#xe756;</i></blockquote>
        <table class="layui-table mag0" lay-skin="line">
            <colgroup>
                <col>
                <col width="110">
            </colgroup>
            <tbody class="hot_news"></tbody>
        </table>
    </div>
</div>
<!-- 查看公告的div -->
<div id="desk_viewNewsDiv" style="padding: 10px;display: none;">
    <h2 id="view_title" align="center"></h2>
    <hr>
    <div style="text-align: right;">
        发布人:<span id="view_opername"></span>
        <span style="display: inline-block;width: 20px" ></span>
        发布时间:<span id="view_createtime"></span>
    </div>
    <hr>
    <div id="view_content"></div>
</div>

<script type="text/javascript" src="${leiyujia}/static/layui/layui.js"></script>
<script>

    //获取系统时间
    var newDate = '';
    getLangDate();
    //值小于10时,在前面补0
    function dateFilter(date){
        if(date < 10){return "0"+date;}
        return date;
    }
    function getLangDate(){
        var dateObj = new Date(); //表示当前系统时间的Date对象
        var year = dateObj.getFullYear(); //当前系统时间的完整年份值
        var month = dateObj.getMonth()+1; //当前系统时间的月份值
        var date = dateObj.getDate(); //当前系统时间的月份中的日
        var day = dateObj.getDay(); //当前系统时间中的星期值
        var weeks = ["星期日","星期一","星期二","星期三","星期四","星期五","星期六"];
        var week = weeks[day]; //根据星期值,从数组中获取对应的星期字符串
        var hour = dateObj.getHours(); //当前系统时间的小时值
        var minute = dateObj.getMinutes(); //当前系统时间的分钟值
        var second = dateObj.getSeconds(); //当前系统时间的秒钟值
        var timeValue = "" +((hour >= 12) ? (hour >= 18) ? "晚上" : "下午" : "上午" ); //当前时间属于上午、晚上还是下午
        newDate = dateFilter(year)+"年"+dateFilter(month)+"月"+dateFilter(date)+"日 "+" "+dateFilter(hour)+":"+dateFilter(minute)+":"+dateFilter(second);
        document.getElementById("nowTime").innerHTML = "亲爱的${user.realname},"+timeValue+"好! 欢迎使用雷神汽车租赁系统。当前时间为: "+newDate+" "+week;
        setTimeout("getLangDate()",1000);
    }

    layui.use(['form','element','layer','jquery'],function(){
        var form = layui.form,
            layer = parent.layer === undefined ? layui.layer : top.layer,
            element = layui.element;
        $ = layui.jquery;
        //上次登录时间【此处应该从接口获取,实际使用中请自行更换】
        $(".loginTime").html(newDate.split("日")[0]+"日</br>"+newDate.split("日")[1]);
        //icon动画
        $(".panel a").hover(function(){
            $(this).find(".layui-anim").addClass("layui-anim-scaleSpring");
        },function(){
            $(this).find(".layui-anim").removeClass("layui-anim-scaleSpring");
        })
        $(".panel a").click(function(){
            parent.addTab($(this));
        })
        //最新文章列表
        $.get("${leiyujia}/news/loadAllNews.action?page=1&limit=10",function(data){
            var hotNewsHtml = '';
            for(var i=0;i<5;i++){
                hotNewsHtml += '<tr οndblclick="viewNews('+data.data[i].id+')">'
                    +'<td align="left"><a href="javascript:;"> '+data.data[i].title+'</a></td>'
                    +'<td>'+data.data[i].createtime.substring(0,10)+'</td>'
                    +'</tr>';
            }
            $(".hot_news").html(hotNewsHtml);
            $(".userAll span").text(data.length);
        })

    });

    function viewNews(id){
        $.get("${leiyujia}/news/loadNewsById.action",{id:id},function(news){
            layer.open({
                type:1,
                title:'查看公告',
                content:$("#desk_viewNewsDiv"),
                area:['800px','550px'],
                success:function(index){
                    $("#view_title").html(news.title);
                    $("#view_opername").html(news.opername);
                    $("#view_createtime").html(news.createtime);
                    $("#view_content").html(news.content);
                }
            });
        });
    }

</script>
</body>
</html>

3.修改system/main/index.jsp

将工作台的控制器地址添加到相应的位置

左边导航栏菜单开发

明确什么是左边的导航栏菜单

开发左边的导航栏菜单要明确的是:

  • LayUI默认支持的是两级菜单
因此默认支持两级菜单,因此我们把pid=1的作为根节点
  • 要在页面中中显示该菜单的样式,那么必须满足菜单的数据格式,将数据库中查询得到的数据封装为菜单要求的数据格式
  • 不同的用户我们希望进来的时候看的菜单是不一样的,那么在现实菜单是要判断用户的角色
  • LayUI菜单数据要求的json数据格式是一个标准json,是有层级关系的,而我们在数据库中存储的菜单数据是没有层级关系的,因此需要利用id和pid来组装层级关系.
  • 对于菜单的开发涉及两个方面:
    1. 因为前台需要后台通过查询来返回一个json数据,然后前端拿到json数据,然后渲染菜单.需要菜单控制给前端返回一个json数据格式的数据
    2. 菜单有的另一个功能,就是菜单能够转跳到其他对应的页面.控制器控制跳转页面的功能

创建Menu菜单实体类

菜单的实体类

  • 对应数据属性创建
package per.leiyu.sys.domain;

public class Menu {
    private Integer id;

    private Integer pid;

    private String title;

    private String href;

    private Integer spread;

    private String target;

    private String icon;

    private Integer available;

    public Menu() {
    }

    public Menu(Integer id, Integer pid, String title, String href, Integer spread, String target, String icon, Integer available) {
        this.id = id;
        this.pid = pid;
        this.title = title;
        this.href = href;
        this.spread = spread;
        this.target = target;
        this.icon = icon;
        this.available = available;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Integer getPid() {
        return pid;
    }

    public void setPid(Integer pid) {
        this.pid = pid;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title == null ? null : title.trim();
    }

    public String getHref() {
        return href;
    }

    public void setHref(String href) {
        this.href = href == null ? null : href.trim();
    }

    public Integer getSpread() {
        return spread;
    }

    public void setSpread(Integer spread) {
        this.spread = spread;
    }

    public String getTarget() {
        return target;
    }

    public void setTarget(String target) {
        this.target = target == null ? null : target.trim();
    }

    public String getIcon() {
        return icon;
    }

    public void setIcon(String icon) {
        this.icon = icon == null ? null : icon.trim();
    }

    public Integer getAvailable() {
        return available;
    }

    public void setAvailable(Integer available) {
        this.available = available;
    }
}

创建MenuVo

作为Menu的视图层对象

可添加分页属性等,这里不需要添加

package per.leiyu.sys.vo;


import per.leiyu.sys.domain.Menu;

public class MenuVo extends Menu {
	
}

创建MenuMapper

package per.leiyu.sys.mapper;


import org.apache.ibatis.annotations.Param;
import per.leiyu.sys.domain.Menu;

import java.util.List;

public interface MenuMapper {
    int deleteByPrimaryKey(Integer id);

    int insert(Menu record);

    int insertSelective(Menu record);

    Menu selectByPrimaryKey(Integer id);

    int updateByPrimaryKeySelective(Menu record);

    int updateByPrimaryKey(Menu record);

    /** * 查询所有菜单 */
    List<Menu> queryAllMenu(Menu menu);

    /** * 根据pid查询菜单数量 * @param pid * @return */
    Integer queryMenuByPid(@Param("pid") Integer pid);
	
}

创建MenuMapper.xml

<?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="per.leiyu.sys.mapper.MenuMapper">
  <resultMap id="BaseResultMap" type="per.leiyu.sys.domain.Menu">
    <id column="id" jdbcType="INTEGER" property="id" />
    <result column="pid" jdbcType="INTEGER" property="pid" />
    <result column="title" jdbcType="VARCHAR" property="title" />
    <result column="href" jdbcType="VARCHAR" property="href" />
    <result column="spread" jdbcType="INTEGER" property="spread" />
    <result column="target" jdbcType="VARCHAR" property="target" />
    <result column="icon" jdbcType="VARCHAR" property="icon" />
    <result column="available" jdbcType="INTEGER" property="available" />
  </resultMap>
  <sql id="Base_Column_List">
    id, pid, title, href, spread, target, icon, available
  </sql>
  <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
    select 
    <include refid="Base_Column_List" />
    from sys_menu
    where id = #{id,jdbcType=INTEGER}
  </select>
  <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
    delete from sys_menu
    where id = #{id,jdbcType=INTEGER}
  </delete>
  <insert id="insert" parameterType="per.leiyu.sys.domain.Menu">
    insert into sys_menu (id, pid, title, 
      href, spread, target, 
      icon, available)
    values (#{id,jdbcType=INTEGER}, #{pid,jdbcType=INTEGER}, #{title,jdbcType=VARCHAR}, 
      #{href,jdbcType=VARCHAR}, #{spread,jdbcType=INTEGER}, #{target,jdbcType=VARCHAR}, 
      #{icon,jdbcType=VARCHAR}, #{available,jdbcType=INTEGER})
  </insert>
  <insert id="insertSelective" parameterType="per.leiyu.sys.domain.Menu">
    insert into sys_menu
    <trim prefix="(" suffix=")" suffixOverrides=",">
      <if test="id != null">
        id,
      </if>
      <if test="pid != null">
        pid,
      </if>
      <if test="title != null">
        title,
      </if>
      <if test="href != null">
        href,
      </if>
      <if test="spread != null">
        spread,
      </if>
      <if test="target != null">
        target,
      </if>
      <if test="icon != null">
        icon,
      </if>
      <if test="available != null">
        available,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides=",">
      <if test="id != null">
        #{id,jdbcType=INTEGER},
      </if>
      <if test="pid != null">
        #{pid,jdbcType=INTEGER},
      </if>
      <if test="title != null">
        #{title,jdbcType=VARCHAR},
      </if>
      <if test="href != null">
        #{href,jdbcType=VARCHAR},
      </if>
      <if test="spread != null">
        #{spread,jdbcType=INTEGER},
      </if>
      <if test="target != null">
        #{target,jdbcType=VARCHAR},
      </if>
      <if test="icon != null">
        #{icon,jdbcType=VARCHAR},
      </if>
      <if test="available != null">
        #{available,jdbcType=INTEGER},
      </if>
    </trim>
  </insert>
  <update id="updateByPrimaryKeySelective" parameterType="per.leiyu.sys.domain.Menu">
    update sys_menu
    <set>
      <if test="pid != null">
        pid = #{pid,jdbcType=INTEGER},
      </if>
      <if test="title != null">
        title = #{title,jdbcType=VARCHAR},
      </if>
      <if test="href != null">
        href = #{href,jdbcType=VARCHAR},
      </if>
      <if test="spread != null">
        spread = #{spread,jdbcType=INTEGER},
      </if>
      <if test="target != null">
        target = #{target,jdbcType=VARCHAR},
      </if>
      <if test="icon != null">
        icon = #{icon,jdbcType=VARCHAR},
      </if>
      <if test="available != null">
        available = #{available,jdbcType=INTEGER},
      </if>
    </set>
    where id = #{id,jdbcType=INTEGER}
  </update>
  <update id="updateByPrimaryKey" parameterType="per.leiyu.sys.domain.Menu">
    update sys_menu
    set pid = #{pid,jdbcType=INTEGER},
      title = #{title,jdbcType=VARCHAR},
      href = #{href,jdbcType=VARCHAR},
      spread = #{spread,jdbcType=INTEGER},
      target = #{target,jdbcType=VARCHAR},
      icon = #{icon,jdbcType=VARCHAR},
      available = #{available,jdbcType=INTEGER}
    where id = #{id,jdbcType=INTEGER}
  </update>

  <!--查询所有菜单-->
  <select id="queryAllMenu" resultMap="BaseResultMap">
    select
    <include refid="Base_Column_List" />
    from sys_menu
    <where>
        <if test="title!=null and title!=''">
            and title like concat("%",#{title},"%")
        </if>
        <if test="available!=null">
            and available=#{available}
        </if>
        <if test="id!=null">
            and (id=#{id} or pid=#{id})
        </if>
    </where>

  </select>

  <!--根据pid查询菜单数量-->
  <select id="queryMenuByPid" resultType="java.lang.Integer">
    select count(1) from sys_menu where pid=#{pid}
  </select>


</mapper>

创建MenuService

提供查询所有菜单的方法

package per.leiyu.sys.service;


import per.leiyu.sys.domain.Menu;
import per.leiyu.sys.utils.DataGridView;
import per.leiyu.sys.vo.MenuVo;

import java.util.List;

/** * 菜单管理的服务接口 */
public interface IMenuService {

    /** * 查询所有菜单返回 * @param menuVo * @return */
    public List<Menu> queryAllMenuForList(MenuVo menuVo);

}

创建TreeNode

是Layui要求json数据格式的实体类,作为菜单数据的工具类.

  • 把菜单数据组装成Layui要求简单json数据(无分层)
package per.leiyu.sys.utils;

import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.ArrayList;
import java.util.List;

/** * @author leiyu */
public class TreeNode {
    private Integer id;
    @JsonProperty("parentId")
    private Integer pid;

    private String title;
    private String icon;
    private String href;
    private Boolean spread;
    private String target;
    private List<TreeNode> children = new ArrayList<>();


    /** * 首页左边导航树的构造器 * @param id * @param pid * @param title * @param icon * @param href * @param spread * @param target */
    public TreeNode(Integer id, Integer pid, String title, String icon, String href, Boolean spread, String target) {
        this.id = id;
        this.pid = pid;
        this.title = title;
        this.icon = icon;
        this.href = href;
        this.spread = spread;
        this.target = target;
    }



    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Integer getPid() {
        return pid;
    }

    public void setPid(Integer pid) {
        this.pid = pid;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getIcon() {
        return icon;
    }

    public void setIcon(String icon) {
        this.icon = icon;
    }

    public String getHref() {
        return href;
    }

    public void setHref(String href) {
        this.href = href;
    }

    public Boolean getSpread() {
        return spread;
    }

    public void setSpread(Boolean spread) {
        this.spread = spread;
    }

    public String getTarget() {
        return target;
    }

    public void setTarget(String target) {
        this.target = target;
    }

    public List<TreeNode> getChildren() {
        return children;
    }

    public void setChildren(List<TreeNode> children) {
        this.children = children;
    }

}

创建TreeNodeBuilder

用于把菜单的简单json数据格式,组装成Layui要求的标准的数据格式

package per.leiyu.sys.utils;


import java.util.ArrayList;
import java.util.List;

/** * @author leiyu */
public class TreeNodeBuilder {

    public static List<TreeNode> builder(List<TreeNode> nodes,Integer topPid){
        List<TreeNode> treeNodes = new ArrayList<>();
        for (TreeNode n1 : nodes) {
            if (n1.getPid() == topPid){
                treeNodes.add(n1);
            }
            for (TreeNode n2 : nodes){
                if (n2.getPid() == n1.getId()){
                    n1.getChildren().add(n2);
                }
            }
        }
        return treeNodes;
    }
}


创建MenuServiceImpl

实现查询所有可用菜单的实现类

package per.leiyu.sys.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import per.leiyu.sys.domain.Menu;
import per.leiyu.sys.mapper.MenuMapper;
import per.leiyu.sys.service.IMenuService;
import per.leiyu.sys.utils.DataGridView;
import per.leiyu.sys.vo.MenuVo;

import java.util.List;

@Service
public class MenuServiceImpl implements IMenuService {

    @Autowired
    private MenuMapper menuMapper;

    /** * 查询所有菜单返回 * @param menuVo * @return */
    @Override
    public List<Menu> queryAllMenuForList(MenuVo menuVo) {
        return menuMapper.queryAllMenu(menuVo);
    }

}

创建MenuController

我们这个Controller的作用就是返回给前端Json数据,用于前端用我们返回的json数据给我构造菜单树,因此设置的是RestController的风格,返回的都是json数据格式这就不能转跳,我们需要重新创建一个Controller来实现跳转用于将简单的集合转化为有层级关系的集合对应的使用时在数据库中查询菜单表,然后把菜单表(菜单表中午层次关系)根绝id 和pid组建为有层级关系的集合,然后就可以在页面中展示为有层级关系的类

package per.leiyu.sys.controller;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import per.leiyu.sys.constast.SysConstast;
import per.leiyu.sys.domain.Menu;
import per.leiyu.sys.domain.User;
import per.leiyu.sys.service.IMenuService;
import per.leiyu.sys.utils.*;
import per.leiyu.sys.vo.MenuVo;

import java.util.ArrayList;
import java.util.List;

/** * 菜单管理控制器 * * 用于返回Json类型的数据 */
@RestController
@RequestMapping("menu")
public class MenuController {

    @Autowired
    private IMenuService menuService;

    @RequestMapping("loadIndexleftMenuJson")
    public List<TreeNode> loadIndexLeftMenuJson(MenuVo menuVo){
        //得到当前登陆的用户对象
        User user =(User) WebUtils.getHttpSession().getAttribute("user");

        List<Menu> list = null;
        menuVo.setAvailable(SysConstast.AVAILABLE_TRUE);//只查询可用的
        if(user.getType()==SysConstast.USER_TYPE_SUPER){
            list = this.menuService.queryAllMenuForList(menuVo);
        }else {
            list = this.menuService.queryMenuByUserIdForList(menuVo,user.getUserid());
        }

        List<TreeNode> nodes = new ArrayList<>();

        //把list里面的数据放到nodes中
        for (Menu menu: list) {
            Integer id = menu.getId();
            Integer pid = menu.getPid();
            String title = menu.getTitle();
            String icon = menu.getIcon();
            String href = menu.getHref();
            Boolean spread = menu.getSpread()==SysConstast.SPREAD_TRUE?true:false;
            String target = menu.getTarget();
            nodes.add(new TreeNode(id,pid,title,icon,href,spread,target));
        }

        return TreeNodeBuilder.builder(nodes,1);
    }


}

修改index.jsp中相应的地址

之前在index,jsp中访问菜单栏我们使用的是静态的就送数据,并非我们数据库中发送的就送数据,现在将其改变为我们的后端发送json数据的handler的地址

总结一下:

  • 菜单开发过程中我们首先明确一定要创建的或者讲,在前后端交互过程中红我们一定要注意的点
    1. 实体类一定要创建
    2. 实体类的视图增强类一定要创建(视图增强类继承了实体类,能使用实体类的所有属性和方法,但是因为是继承关系,其又可在实体类的基础上添加新的属性和方法)
      • 虽然是继承关系,有一定的耦合度,但是实体类是完全和数据库对应的,而视图增强类又不被其他类所继承,因此耦合度虽然有,但是发生错误的可能性很小.又可以对实体类增强,便于分页查询或者批量删除.
      • 不在实体类中直接添加这些与数据库中数据毫无关系的逻辑性数据是一种比较好的习惯.也便于sql语句的书写.
    3. 前端访问Controller的handler时,该handler可以向前端返回一个符合前端json数据格式的json数据,这就实现了从前端请求,到后端业务操作再响应给后端的过程
    4. 左侧导航栏菜单的开发中只涉及到从后端传数据到前端,也就是通过handler发送json数据到前端,前端再渲染,之后有些功能就涉及到了需要先从后端请求数据发送到前端渲染,然后前端再操作收据到后端保存
    5. 在菜单开发过程中,不知道大家有么有仔细观察:我们虽然把pid=1的数据作为根节点,也就是说pid=0的数据(车辆租赁系统是无效的数据,在菜单加载发送数据中是无效的数据),我们在查询时却查询的是所有的菜单数据,并没有过滤掉pid=0的数据,这是因为之后的功能也要使用到查询所有菜单的数据,因此为了开发复用性,我们查出所有的数据,然后在service层进行过滤
    6. 关于Service层的说明:Service层时完成业务逻辑功能的层级,把简单的sql语句进行拼接完成复杂的逻辑,或者在service层处理一些有关数据处理相关的内容
    7. Controller层:总体来讲两个作用
      1. 跳转
      2. 发送json数据

我是雷雨,一个普本科的学生,主要专注于Java后端和大数据开发

如果你喜欢这样的文章,可以关注我,一起努力,一起努力拿大厂offer
如果这篇文章有帮助到你,希望你给我一个的赞
如果有什么问题,希望你能评论区和我一起研究.

如果您要转载请转载注明出处
https://blog.csdn.net/qq_40742223