六、模块实现:登录控制模块(4)

    1. 登录控制模块
      1. 登录拦截器

在包“com.example.demo”中新建一个“LoginInterceptor”类,代码如下:

package com.example.demo;

import java.io.PrintWriter;

 

/**

 * 登录拦截器

 */

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.servlet.http.HttpSession;

 

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Component;

import org.springframework.web.servlet.HandlerInterceptor;

 

import com.example.demo.vo.Json;

import com.fasterxml.jackson.databind.ObjectMapper;

 

@Component

public class LoginInterceptor implements HandlerInterceptor {

   

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

 

    @Autowired

    private ObjectMapper mapper;//Jackson使用ObjectMapper类将POJO对象序列化成JSON字符串,也能将JSON字符串反序列化成POJO对象。

 

    @Override

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {       //请求进入这个拦截器

         logger.info("进入拦截器...");

         HttpSession session = request.getSession();

        if(session.getAttribute("user") == null){//判断session中有没有user信息

        logger.info("session中没有user信息");

        //ajax异步请求

            if("XMLHttpRequest".equalsIgnoreCase(request.getHeader("X-Requested-With"))){

              logger.info("ajax异步请求");

              Json j = new Json();

              j.setSuccess(false);

              j.setMsg("session会话超时,请重新登录!");

              response.setContentType("application/json;charset=UTF-8");

                  PrintWriter writer = response.getWriter();

                  writer.write(mapper.writeValueAsString(j));//将对象转成字符串

                  logger.info(mapper.writeValueAsString(j));

                  writer.close();

                  response.flushBuffer();

                  return false;

            }else {

              logger.info("页面请求");

              response.sendRedirect("/login");//没有user信息的话进行路由重定向到登录页面

                return false;

            }

        }

        logger.info("登录拦截验证通过。");

        return true;//有的话就继续操作

    }

}

每一个配置为拦截的http请求都会执行preHandle方法,可以在这里检查用户的session是否为空来进行登录验证,因为请求有可能是异步的,所以对于异步的请求不能直接跳转页面,而是返回json数据。

修改在包“com.example.demo”中新建一个“WebConfig”类,代码如下:

package com.example.demo;

 

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.context.annotation.Configuration;

import org.springframework.web.servlet.config.annotation.InterceptorRegistration;

import org.springframework.web.servlet.config.annotation.InterceptorRegistry;

import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;

import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

 

@Configuration

public class WebConfig implements WebMvcConfigurer {

   

    @Autowired

    private LoginInterceptor loginInterceptor;//登录拦截器

 

    //图片存放根路径,从application.yml中读取upload

    @Value("${upload}")

    private String UPLOAD_PATH;

   

    /**

     * 文件上传

     */

    @Override

    public void addResourceHandlers(ResourceHandlerRegistry registry) {

    //外部静态资源映射路径,用来上传文件

    String filePath = "file:" + UPLOAD_PATH;

        registry.addResourceHandler("/upload/**").addResourceLocations(filePath);

    }

   

    //拦截器

    @Override

    public void addInterceptors(InterceptorRegistry registry) {

        //登录拦截的管理器

        InterceptorRegistration registration = registry.addInterceptor(loginInterceptor);//拦截的对象会进入这个类中进行判断

        registration.addPathPatterns("/**");//所有路径都被拦截

        registration.excludePathPatterns("/","/login","/UserController/login","/kaptcha","/static/**","/UserController/logout","/upload/**");//添加不拦截路径

    }

}

在WebConfig中增加了拦截器的设置。

      1. 验证码接口

修改在包“com.example.demo.controller”中新建一个“HomeController”类,代码如下:

package com.example.demo.controller;

/**

 * 后台管理主页,登录页面,验证码生成

 */

import java.awt.image.BufferedImage;

import javax.imageio.ImageIO;

import javax.servlet.ServletOutputStream;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.servlet.http.HttpSession;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Controller;

import org.springframework.ui.Model;

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

import org.springframework.web.servlet.ModelAndView;

import com.example.demo.model.User;

import com.example.demo.service.PermissionService;

import com.google.code.kaptcha.Constants;

import com.google.code.kaptcha.Producer;

 

@Controller

public class HomeController {

 

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

   

    @Autowired 

    private Producer captchaProducer;//验证码

   

    @Autowired

    private PermissionService permissionService;// 注入业务层的service

   

    // 未加入@ResponseBody用来返回数据给页面

    @RequestMapping("/index")

    public String index(HttpServletRequest request,Model model) {

         HttpSession session = request.getSession();

         User user = (User)session.getAttribute("user");

         logger.info(user.getUsername());

         logger.info(user.getId());

         model.addAttribute("username", user.getUsername());

         model.addAttribute("userid", user.getId());

         model.addAttribute("menulist", permissionService.getUserMenu(user.getId()));

         return "admin/index";

    }

 

    // 未加入@ResponseBody用来返回数据给页面

    @RequestMapping("/home")

    public String home(Model model) {

         return "admin/home";

    }

   

    // 未加入@ResponseBody用来返回数据给页面

    @RequestMapping("/")

    public String login(Model model) {

         return "admin/login";

    }

   

    // 未加入@ResponseBody用来返回数据给页面

    @RequestMapping("/login")

    public String login2(Model model) {

         return "admin/login";

    }

   

    @RequestMapping("/kaptcha"

    public ModelAndView getKaptchaImage(HttpServletRequest request, HttpServletResponse response) throws Exception {   

        HttpSession session = request.getSession();   

        String code = (String)session.getAttribute(Constants.KAPTCHA_SESSION_KEY);   

        logger.info("******************验证码是: " + code + "******************");   

        response.setDateHeader("Expires", 0);   

        // Set standard HTTP/1.1 no-cache headers.   

        response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");   

        // Set IE extended HTTP/1.1 no-cache headers (use addHeader).   

        response.addHeader("Cache-Control", "post-check=0, pre-check=0");   

        // Set standard HTTP/1.0 no-cache header.   

        response.setHeader("Pragma", "no-cache");   

        // return a jpeg   

        response.setContentType("image/jpeg");   

        // create the text for the image   

        String capText = captchaProducer.createText();   

        // store the text in the session   

        session.setAttribute(Constants.KAPTCHA_SESSION_KEY, capText);   

        // create the image with the text   

        BufferedImage bi = captchaProducer.createImage(capText);   

        ServletOutputStream out = response.getOutputStream();   

        // write the data out   

        ImageIO.write(bi, "jpg", out);   

        try {   

            out.flush();   

        } finally {   

            out.close();   

        }   

        return null;   

    }

 

}

增加了登录页面路径映射以及验证码生成接口。

修改在包“com.example.demo”中新建一个“MisApplication”类,代码如下:

package com.example.demo;

 

import java.util.Properties;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.context.annotation.Bean;

import com.google.code.kaptcha.Constants;

import com.google.code.kaptcha.impl.DefaultKaptcha;

import com.google.code.kaptcha.util.Config;

 

@SpringBootApplication

public class MisApplication {

 

    public static void main(String[] args) {

         SpringApplication.run(MisApplication.class, args);

    }

   

    /**

     * 验证码

     * @return

     */

    @Bean 

    public DefaultKaptcha captchaProducer() { 

        DefaultKaptcha captchaProducer = new DefaultKaptcha(); 

        Properties properties = new Properties(); 

//      properties.setProperty(Constants.KAPTCHA_BORDER, "yes"); 

//      properties.setProperty(Constants.KAPTCHA_BORDER_COLOR, "red"); 

//      properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue"); 

        properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_FONT_SIZE, "50"); 

        properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_FONT_NAMES, "宋体,楷体,微软雅黑"); 

        properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4"); 

        properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_CHAR_STRING, "0123456789"); 

        properties.setProperty(Constants.KAPTCHA_IMAGE_WIDTH, "120"); 

        properties.setProperty(Constants.KAPTCHA_IMAGE_HEIGHT, "50"); 

        properties.setProperty(Constants.KAPTCHA_SESSION_CONFIG_KEY, "code"); 

        Config config = new Config(properties); 

        captchaProducer.setConfig(config); 

        return captchaProducer

    } 

 

}

对验证码的生成进行配置。

      1. 登录与注销接口

修改在包“com.example.demo.controller”中新建一个“UserController”类,代码如下:

package com.example.demo.controller;

 

import java.io.File;

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpSession;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.stereotype.Controller;

import org.springframework.ui.Model;

import org.springframework.util.StringUtils;

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

import org.springframework.web.bind.annotation.RequestParam;

import org.springframework.web.bind.annotation.ResponseBody;

import org.springframework.web.multipart.MultipartFile;

 

import com.example.demo.model.User;

import com.example.demo.service.UserService;

import com.example.demo.util.SnowflakeIdWorker;

import com.example.demo.vo.DataTableResult;

import com.example.demo.vo.Json;

import com.example.demo.vo.UserVO;

import com.google.code.kaptcha.Constants;

 

@Controller

@RequestMapping("/UserController")

public class UserController {

 

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

 

    private String prefix = "admin/user";// 页面的路径,注意admin前面不要有/

 

    // 图片存放根路径,从application.yml中读取upload

    @Value("${upload}")

    private String UPLOAD_PATH;

 

    @Autowired

    private UserService userService;// 注入业务层的service

 

    // 未加入@ResponseBody用来返回数据给页面

    @RequestMapping("view")

    public String view(Model model) {

//       String str="个人";

//       model用来回传数据给前端页面

//       setTitle(model, new TitleVo("列表", str+"管理", true,"欢迎进入"+str+"页面", true, false));

         return prefix + "/view";

    }

 

    // @ResponseBody,直接通过js异步返回数据给页面

    @RequestMapping("list")

    @ResponseBody

    public DataTableResult list(HttpServletRequest request, UserVO userVO) {

         // DataTableResult返回给datatables控件的数据格式

         DataTableResult result = new DataTableResult();

         // 获取分页参数

         int start = Integer.parseInt(request.getParameter("start"));

         int length = Integer.parseInt(request.getParameter("length"));

         // 获取排序字段

         String orderIdx = request.getParameter("order[0][column]");

         // 获取排序字段名

         String orderField = request.getParameter("columns[" + orderIdx + "][name]");

         // 获取排序方式,降序desc或者升序asc

         String orderDir = request.getParameter("order[0][dir]");

         // 调用分页查询方法

         result = userService.selectUserListPage(userVO, start, length, orderField, orderDir);

//       result.setDraw(userVO.getDraw());

         return result;

    }

    // @ResponseBody,直接通过js异步返回数据给页面

    @RequestMapping("insert")

    @ResponseBody

    public Json insert(User user) {

         Json j = new Json();

         if (userService.insert(user) > 0) {

             j.setSuccess(true);

             j.setMsg("添加成功!");

         } else {

             j.setSuccess(false);

             j.setMsg("添加失败!");

         }

         return j;

    }

 

    // @ResponseBody,直接通过js异步返回数据给页面

    @RequestMapping("update")

    @ResponseBody

    public Json updateById(User user) {

         Json j = new Json();

         if (userService.updateById(user) > 0) {

             j.setSuccess(true);

             j.setMsg("修改成功!");

         } else {

             j.setSuccess(false);

             j.setMsg("修改失败!");

         }

         return j;

    }

 

    // @ResponseBody,直接通过js异步返回数据给页面

    @RequestMapping("select")

    @ResponseBody

    public Json selectById(User user) {

         Json j = new Json();

         j.setSuccess(true);

         j.setObj(userService.selectById(user.getId()));

         return j;

    }

 

    // @ResponseBody,直接通过js异步返回数据给页面

    @RequestMapping("delete")

    @ResponseBody

    public Json delete(HttpServletRequest request) {

         Json j = new Json();

         String ids = request.getParameter("ids");

         if (!StringUtils.isEmpty(ids)) {

             j.setSuccess(true);

             j.setObj("成功删除" + userService.delete(ids) + "条记录");

         } else {

             j.setSuccess(false);

             j.setMsg("没有需要删除的记录!");

         }

         return j;

    }

 

    // @ResponseBody,直接通过js异步返回数据给页面

    // @RequestParam("file[]") MultipartFile[] file 多个文件

    @RequestMapping("upload")

    @ResponseBody

    public Json upload(HttpServletRequest request, @RequestParam("file") MultipartFile file) {

         Json j = new Json();

         if (!file.isEmpty()) {

             try {

                  String originalFilename = file.getOriginalFilename();

                  // 随机文件名

                  String newFileName = SnowflakeIdWorker.getUUID()

                          + originalFilename.substring(originalFilename.lastIndexOf("."));

                  // 上传文件路径

                  File upload = new File(UPLOAD_PATH, "images/");

                 if (!upload.exists())

                      upload.mkdirs();

                  String uploadPath = upload + "\\";

                  logger.info("uploadPath = " + uploadPath);

                  File uploadfile = new File(uploadPath + newFileName);

                  // 将上传文件保存到一个目标文件当中

                  file.transferTo(uploadfile);

                  j.setSuccess(true);

                  j.setObj("/upload/images/" + newFileName);

             } catch (IllegalStateException | IOException e) {

                  // TODO Auto-generated catch block

                  e.printStackTrace();

                  j.setSuccess(false);

                  j.setObj("上传异常");

             }

 

         } else {

             j.setSuccess(false);

             j.setObj("上传失败");

         }

         return j;

    }

 

    /**

     * 登录验证

     * @param request

     * @param user

     * @return

     */

    // @ResponseBody,直接通过js异步返回数据给页面

    @RequestMapping("login")

    @ResponseBody

    public Json login(HttpServletRequest request, User user) {

         Json j = new Json();

         HttpSession session = request.getSession();

         String code = (String) session.getAttribute(Constants.KAPTCHA_SESSION_KEY);

         String kaptcha = request.getParameter("kaptcha");

         if (kaptcha.equals(code)) {

             // 验证码正确

             User loginUser = userService.selectByUser(user);

             if (loginUser != null) {

                  j.setSuccess(true);

                  loginUser.setPassword("");// 密码不回传

                  j.setObj(loginUser);

                  j.setMsg("登录成功!");

                  session.setAttribute("user", loginUser);// 保存session会话

             } else {

                  j.setSuccess(false);

                  j.setMsg("登录失败!");

             }

         } else {

             j.setSuccess(false);

             j.setMsg("验证码错误!");

         }

         return j;

    }

 

    /**

     * 注销

     * @param request

     * @param model

     * @return

     */

    // 未加入@ResponseBody用来返回数据给页面

    @RequestMapping("logout")

    public String logout(HttpServletRequest request,Model model) {

         HttpSession session = request.getSession();

         session.removeAttribute("user");

         return "admin/login";

    }

 

}

增加了用户登录与注销接口。

      1. 登录界面

添加登录界面文件,在“admin”文件夹-> 右键->new->file,输入“login.html”,代码如下:

<!DOCTYPE html>

<html xmlns:th="http://www.thymeleaf.org">

<head>

    <meta charset="utf-8">

    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">

 

    <title> - 登录</title>

    <meta name="keywords" content="">

    <meta name="description" content="">

    <link th:href="@{/static/css/bootstrap.min.css}" rel="stylesheet">

    <link th:href="@{/static/css/font-awesome.css?v=4.4.0}" rel="stylesheet">

    <link th:href="@{/static/css/animate.css}" rel="stylesheet">

    <link th:href="@{/static/css/style.css}" rel="stylesheet">

    <link th:href="@{/static/css/login.css}" rel="stylesheet">

    <!-- toastr -->

    <link th:href="@{/static/css/plugins/toastr/toastr.min.css}" rel="stylesheet">   

    <!--[if lt IE 9]>

    <meta http-equiv="refresh" content="0;ie.html" />

    <![endif]-->

    <script>

        if (window.top !== window.self) {

            window.top.location = window.location;

        }

    </script>

 

</head>

 

<body class="signin">

    <div class="signinpanel">

        <div class="row">

            <div class="col-sm-12">

                <form>

                    <h4 class="no-margins">登录:</h4>

                    <p class="m-t-md">登录XXX后台管理系统</p>

                    <input type="text" name="username" id="username" class="form-control uname" placeholder="用户名" />

                    <input type="password" name="password" id="password" class="form-control pword m-b" placeholder="密码" />

                    <div class="input-group" style="margin-top:15px;color:#333;">

                          <input type="text" name="kaptcha" id="kaptcha" class="form-control" style="margin-top:0px;" placeholder="验证码" >

                          <span style="padding:1px;" class="input-group-addon "><img src="/kaptcha" id="kaptchaImage" style="height:30px;vertical-align:middle;" alt="点击刷新" title="点击刷新" onclick='$("#kaptchaImage").attr("src","/kaptcha?r="+Math.random())'></span>

                      </div>

                    <a href="">忘记密码了?</a>

                    <button type="button" id="btn_login" class="btn btn-success btn-block">登录</button>

                </form>

            </div>

        </div>

        <div class="signup-footer">

            <div class="pull-left">

                &copy; 福建江夏学院电子信息科学学院信息管理系,2019

            </div>

        </div>

    </div>

    <!-- 全局js -->

    <script th:src="@{/static/js/jquery.min.js?v=2.1.4}"></script>

    <!-- Toastr script -->

    <script th:src="@{/static/js/plugins/toastr/toastr.min.js}"></script>

    <!-- Page-Level Scripts -->

    <script>

    $(document).ready(function () {

         //toastr选项

    toastr.options = {

       "positionClass": "toast-bottom-center",

    }

        

         $("#btn_login").click(function(){

             var username=$("#username").val();

             var password=$("#password").val();

             var kaptcha=$("#kaptcha").val();

             if(username.length==0 || password.length==0 || kaptcha.length==0){

                  toastr.error("用户名、密码或者验证码为空!", '错误!');

             }else{

                  //异步添加数据

            $.ajax({

                  type: "post",

                  data: {

                      username:$("#username").val(),

                      password:$("#password").val(),

                      kaptcha:$("#kaptcha").val(),

                  },

                  url: "/UserController/login",//后台处理地址

                  success: function (data) {

                     if(data.success){

                         toastr.success(data.msg, '登录成功!');

                         location.href="/index";

                     }else{

                         toastr.error(data.msg, '登录失败!');

                     }

                  }

            });  // end ajax

             }

            

    });//end btn_login

    });//end ready

    </script>

</body>

</html>

 

      1. 动态加载菜单

修改主界面文件,在“admin”文件夹中的“index.html”,代码如下:

<!DOCTYPE html>

<html xmlns:th="http://www.thymeleaf.org">

<head>

    <meta charset="utf-8">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <meta name="renderer" content="webkit">

 

    <title> hAdmin- 主页</title>

 

    <meta name="keywords" content="">

    <meta name="description" content="">

 

    <!--[if lt IE 9]>

    <meta http-equiv="refresh" content="0;ie.html" />

    <![endif]-->

 

    <link rel="shortcut icon" href="favicon.ico">

    <link th:href="@{/static/css/bootstrap.min.css?v=3.3.6}" rel="stylesheet">

    <link th:href="@{/static/css/font-awesome.min.css?v=4.4.0}" rel="stylesheet">

    <link th:href="@{/static/css/animate.css}" rel="stylesheet">

    <link th:href="@{/static/css/style.css?v=4.1.0}" rel="stylesheet">

   

</head>

 

<body class="fixed-sidebar full-height-layout gray-bg" style="overflow:hidden">

    <div id="wrapper">

        <!--左侧导航开始-->

        <nav class="navbar-default navbar-static-side" role="navigation">

            <div class="nav-close"><i class="fa fa-times-circle"></i>

            </div>

            <div class="sidebar-collapse">

                <ul class="nav" id="side-menu">

                    <li class="nav-header">

                        <div class="dropdown profile-element">

                            <a data-toggle="dropdown" class="dropdown-toggle" href="#">

                                <span class="clear">

                                    <span class="block m-t-xs" style="font-size:20px;">

                                        <i class="fa fa-bank"></i>

                                        <strong class="font-bold">管理系统</strong>

                                    </span>

                                </span>

                            </a>

                        </div>

                        <div class="logo-element">管理系统

                        </div>

                    </li>

 

                    <li>

                        <a class="J_menuItem" href="/home">

                            <i class="fa fa-home"></i>

                            <span class="nav-label">主页</span>

                        </a>

                    </li>

                   

                   

 

                   

                    <li th:each="menu,menuStat:${menulist}">

                        <a href="#">

                            <i th:class="${menu.menu.menuIcon}"></i>

                            <span class="nav-label" th:text="${menu.menu.menuText}"></span>

                            <span class="fa arrow"></span>

                        </a>

                        <ul class="nav nav-second-level">

                            <li th:each="submenu,submenuStat:${menu.submenus}">

                                <a class="J_menuItem" th:href="@{${submenu.menuUrl}}" th:text="${submenu.menuText}"></a>

                            </li>

                        </ul>

                    </li>

                   

                 

 

 

                </ul>

            </div>

        </nav>

        <!--左侧导航结束-->

        <!--右侧部分开始-->

        <div id="page-wrapper" class="gray-bg dashbard-1">

            <div class="row border-bottom">

                <nav class="navbar navbar-static-top" role="navigation" style="margin-bottom: 0">

                    <div class="navbar-header"><a class="navbar-minimalize minimalize-styl-2 btn btn-info " href="#"><i class="fa fa-bars"></i> </a>

                        <form role="search" class="navbar-form-custom" method="post" action="search_results.html">

                            <div class="form-group">

                                <input type="text" placeholder="请输入您需要查找的内容 …" class="form-control" name="top-search" id="top-search">

                            </div>

                        </form>

                    </div>

                    <ul class="nav navbar-top-links navbar-right">

                        <li>

                           <span th:text="${username}"></span><span><a href="/UserController/logout">注销</a></span>

                        </li>

                        <li class="dropdown">

                            <a class="dropdown-toggle count-info" data-toggle="dropdown" href="#">

                                <i class="fa fa-envelope"></i> <span class="label label-warning">16</span>

                            </a>

                            <ul class="dropdown-menu dropdown-messages">

                                <li class="m-t-xs">

                                    <div class="dropdown-messages-box">

                                        <a href="profile.html" class="pull-left">

                                            <img alt="image" class="img-circle" th:src="@{/static/img/a7.jpg}">

                                        </a>

                                        <div class="media-body">

                                            <small class="pull-right">46小时前</small>

                                            <strong>小四</strong> 是不是只有我死了,你们才不骂爵迹

                                            <br>

                                            <small class="text-muted">3天前 2014.11.8</small>

                                        </div>

                                    </div>

                                </li>

                                <li class="divider"></li>

                                <li>

                                    <div class="dropdown-messages-box">

                                        <a href="profile.html" class="pull-left">

                                            <img alt="image" class="img-circle" th:src="@{/static/img/a4.jpg}">

                                        </a>

                                        <div class="media-body ">

                                            <small class="pull-right text-navy">25小时前</small>

                                            <strong>二愣子</strong> 呵呵

                                            <br>

                                            <small class="text-muted">昨天</small>

                                        </div>

                                    </div>

                                </li>

                                <li class="divider"></li>

                                <li>

                                    <div class="text-center link-block">

                                        <a class="J_menuItem" href="mailbox.html">

                                            <i class="fa fa-envelope"></i> <strong> 查看所有消息</strong>

                                        </a>

                                    </div>

                                </li>

                            </ul>

                        </li>

                        <li class="dropdown">

                            <a class="dropdown-toggle count-info" data-toggle="dropdown" href="#">

                                <i class="fa fa-bell"></i> <span class="label label-primary">8</span>

                            </a>

                            <ul class="dropdown-menu dropdown-alerts">

                                <li>

                                    <a href="mailbox.html">

                                        <div>

                                            <i class="fa fa-envelope fa-fw"></i> 您有16条未读消息

                                            <span class="pull-right text-muted small">4分钟前</span>

                                        </div>

                                    </a>

                                </li>

                                <li class="divider"></li>

                                <li>

                                    <a href="profile.html">

                                        <div>

                                            <i class="fa fa-qq fa-fw"></i> 3条新回复

                                            <span class="pull-right text-muted small">12分钟钱</span>

                                        </div>

                                    </a>

                                </li>

                                <li class="divider"></li>

                                <li>

                                    <div class="text-center link-block">

                                        <a class="J_menuItem" href="notifications.html">

                                            <strong>查看所有 </strong>

                                            <i class="fa fa-angle-right"></i>

                                        </a>

                                    </div>

                                </li>

                            </ul>

                        </li>

                    </ul>

                </nav>

            </div>

            <div class="row J_mainContent" id="content-main">

                <iframe id="J_iframe" width="100%" height="100%" src="/home" frameborder="0" data-id="/home" seamless></iframe>

            </div>

        </div>

        <!--右侧部分结束-->

    </div>

 

    <!-- 全局js -->

    <script th:src="@{/static/js/jquery.min.js?v=2.1.4}"></script>

    <script th:src="@{/static/js/bootstrap.min.js?v=3.3.6}"></script>

    <script th:src="@{/static/js/plugins/metisMenu/jquery.metisMenu.js}"></script>

    <script th:src="@{/static/js/plugins/slimscroll/jquery.slimscroll.min.js}"></script>

    <script th:src="@{/static/js/plugins/layer/layer.min.js}"></script>

 

    <!-- 自定义js -->

    <script th:src="@{/static/js/hAdmin.js?v=4.1.0}"></script>

    <script type="text/javascript" th:src="@{/static/js/index.js}"></script>

 

    <!-- 第三方插件 -->

    <script th:src="@{/static/js/plugins/pace/pace.min.js}"></script>

 

</body>

 

</html>

利用“th:each”对后台返回的"${menulist}"数据进行二重遍历,动态构造出用户的菜单。

打开浏览器,先输入地址http://127.0.0.1:8080/index,会发现跳转到登录页面,效果如下:

以不同身份登录时菜单不同,以用户名和密码都为“e”登录:

点击右上角的注销链接后,以用户名和密码都为“a”登录:

还可以通过后台动态修改角色的权限和用户的角色,注意首先是对角色分配权限,然后再把角色分配给用户。

完整的项目源码已经分享在GitHub网站上(https://github.com/gjq246/springboot2author)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值