1、springboot整合mybatis、spring security实现登录验证
引用:
SpringBoot集成Spring Security(1)——入门程序
(1)、创建数据库security,数据库没有安装,只是使用的是PHPStudy2016中提供的mysql,所以在pom.xml中使用的5.X的依赖。
/* Navicat MySQL Data Transfer Source Server : localhost Source Server Version : 50553 Source Host : localhost:3306 Source Database : security Target Server Type : MYSQL Target Server Version : 50553 File Encoding : 65001 Date: 2020-10-27 10:37:41 */ SET FOREIGN_KEY_CHECKS=0; -- ---------------------------- -- Table structure for sys_role -- ---------------------------- DROP TABLE IF EXISTS `sys_role`; CREATE TABLE `sys_role` ( `id` int(11) NOT NULL, `name` varchar(255) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of sys_role 角色名称:ROLE_ADMIN固定格式 -- ---------------------------- INSERT INTO `sys_role` VALUES ('1', 'ROLE_ADMIN'); INSERT INTO `sys_role` VALUES ('2', 'ROLE_USER'); -- ---------------------------- -- Table structure for sys_user -- ---------------------------- DROP TABLE IF EXISTS `sys_user`; CREATE TABLE `sys_user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, `password` varchar(255) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of sys_user 其中密码是已经加密后的字符串:123
--可以通过controller的方法输出获取logger.info(new BCryptPasswordEncoder().encode("123"));
-- ---------------------------- INSERT INTO `sys_user` VALUES ('1', 'admin', '$2a$10$lgztJXeAiNHeOvwqIxTsb.7.fl63uvhqobTUVhwKxhUfn.SdWFOtC'); INSERT INTO `sys_user` VALUES ('2', 'user', '$2a$10$lgztJXeAiNHeOvwqIxTsb.7.fl63uvhqobTUVhwKxhUfn.SdWFOtC'); -- ---------------------------- -- Table structure for sys_user_role -- ---------------------------- DROP TABLE IF EXISTS `sys_user_role`; CREATE TABLE `sys_user_role` ( `user_id` int(11) NOT NULL, `role_id` int(11) NOT NULL, PRIMARY KEY (`user_id`,`role_id`), KEY `fk_role_id` (`role_id`), CONSTRAINT `fk_role_id` FOREIGN KEY (`role_id`) REFERENCES `sys_role` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT `fk_user_id` FOREIGN KEY (`user_id`) REFERENCES `sys_user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of sys_user_role -- ---------------------------- INSERT INTO `sys_user_role` VALUES ('1', '1'); INSERT INTO `sys_user_role` VALUES ('2', '2');
(2)、pom.xml依赖
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.4.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>cn.gwj.security</groupId> <artifactId>spring-sercurity-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>spring-sercurity-demo</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.49</version> </dependency> <!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.3</version> </dependency> <!-- https://mvnrepository.com/artifact/org.mybatis.generator/mybatis-generator-core --> <dependency> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-core</artifactId> <version>1.4.0</version> </dependency> <!-- https://mvnrepository.com/artifact/org.mybatis.generator/mybatis-generator-maven-plugin --> <dependency> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-maven-plugin</artifactId> <version>1.4.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <plugin> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-maven-plugin</artifactId> <version>1.4.0</version> <configuration> <configurationFile>src/main/resources/generatorConfig.xml</configurationFile> <overwrite>true</overwrite> <verbose>true</verbose> </configuration> </plugin> </plugins> </build> </project>
(3)、准备页面login.html、index.html,页面及相关资源均放置在static文件夹内。
页面全部文件采用AppWorkv1.4.0页面
login.html,其中input标记,必须指定name属性。
<input type="text" class="form-control" name="username">
<input type="password" class="form-control" name="password">
<input type="checkbox" class="custom-control-input" name="remember-me">
<!DOCTYPE html> <html lang="en" class="default-style"> <head> <title>Login v1 - Pages - Appwork</title> <meta charset="utf-8"> <meta http-equiv="x-ua-compatible" content="IE=edge,chrome=1"> <meta name="description" content=""> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"> <link rel="icon" type="image/x-icon" href="favicon.ico"> <!-- Icon fonts --> <link rel="stylesheet" href="assets/vendor/fonts/fontawesome.css"> <link rel="stylesheet" href="assets/vendor/fonts/ionicons.css"> <link rel="stylesheet" href="assets/vendor/fonts/linearicons.css"> <link rel="stylesheet" href="assets/vendor/fonts/open-iconic.css"> <link rel="stylesheet" href="assets/vendor/fonts/pe-icon-7-stroke.css"> <!-- Core stylesheets --> <link rel="stylesheet" href="assets/vendor/css/rtl/bootstrap.css" class="theme-settings-bootstrap-css"> <link rel="stylesheet" href="assets/vendor/css/rtl/appwork.css" class="theme-settings-appwork-css"> <link rel="stylesheet" href="assets/vendor/css/rtl/theme-corporate.css" class="theme-settings-theme-css"> <link rel="stylesheet" href="assets/vendor/css/rtl/colors.css" class="theme-settings-colors-css"> <link rel="stylesheet" href="assets/vendor/css/rtl/uikit.css"> <link rel="stylesheet" href="assets/css/demo.css"> <!-- Load polyfills --> <script src="assets/vendor/js/polyfills.js"></script> <script src="assets/vendor/js/material-ripple.js"></script> <script src="assets/vendor/js/layout-helpers.js"></script> <!-- Theme settings --> <!-- This file MUST be included after core stylesheets and layout-helpers.js in the <head> section --> <script src="assets/vendor/js/theme-settings.js"></script> <script> window.themeSettings = new ThemeSettings({ cssPath: 'assets/vendor/css/rtl/', themesPath: 'assets/vendor/css/rtl/' }); </script> <!-- Core scripts --> <script src="assets/vendor/js/pace.js"></script> <script src="assets/vendor/libs/jquery-3.2.1.min.js"></script> <!-- Libs --> <link rel="stylesheet" href="assets/vendor/libs/perfect-scrollbar/perfect-scrollbar.css"> <!-- Page --> <link rel="stylesheet" href="assets/vendor/css/pages/authentication.css"> </head> <body> <div class="page-loader"> <div class="bg-primary"></div> </div> <!-- Content --> <div class="authentication-wrapper authentication-1 px-4"> <div class="authentication-inner py-5"> <!-- Logo --> <div class="d-flex justify-content-center align-items-center"> <div class="ui-w-60"> <div class="w-100 position-relative" style="padding-bottom: 54%"> <svg class="w-100 h-100 position-absolute" viewBox="0 0 148 80" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><linearGradient id="a" x1="46.49" x2="62.46" y1="53.39" y2="48.2" gradientUnits="userSpaceOnUse"><stop stop-opacity=".25" offset="0"></stop><stop stop-opacity=".1" offset=".3"></stop><stop stop-opacity="0" offset=".9"></stop></linearGradient><linearGradient id="e" x1="76.9" x2="92.64" y1="26.38" y2="31.49" xlink:href="#a"></linearGradient><linearGradient id="d" x1="107.12" x2="122.74" y1="53.41" y2="48.33" xlink:href="#a"></linearGradient></defs><path class="fill-primary" transform="translate(-.1)" d="M121.36,0,104.42,45.08,88.71,3.28A5.09,5.09,0,0,0,83.93,0H64.27A5.09,5.09,0,0,0,59.5,3.28L43.79,45.08,26.85,0H.1L29.43,76.74A5.09,5.09,0,0,0,34.19,80H53.39a5.09,5.09,0,0,0,4.77-3.26L74.1,35l16,41.74A5.09,5.09,0,0,0,94.82,80h18.95a5.09,5.09,0,0,0,4.76-3.24L148.1,0Z"></path><path transform="translate(-.1)" d="M52.19,22.73l-8.4,22.35L56.51,78.94a5,5,0,0,0,1.64-2.19l7.34-19.2Z" fill="url(#a)"></path><path transform="translate(-.1)" d="M95.73,22l-7-18.69a5,5,0,0,0-1.64-2.21L74.1,35l8.33,21.79Z" fill="url(#e)"></path><path transform="translate(-.1)" d="M112.73,23l-8.31,22.12,12.66,33.7a5,5,0,0,0,1.45-2l7.3-18.93Z" fill="url(#d)"></path></svg> </div> </div> </div> <!-- / Logo --> <!-- Form --> <form class="my-5" method="post" action="/login"> <div class="form-group"> <label class="form-label">UserName</label> <input type="text" class="form-control" name="username"> </div> <div class="form-group"> <label class="form-label d-flex justify-content-between align-items-end"> <div>Password</div> <a href="javascript:void(0)" class="d-block small">Forgot password?</a> </label> <input type="password" class="form-control" name="password"> </div> <div class="d-flex justify-content-between align-items-center m-0"> <label class="custom-control custom-checkbox m-0"> <input type="checkbox" class="custom-control-input" name="remember-me"> <span class="custom-control-label">Remember me</span> </label> <button type="submit" class="btn btn-primary">Sign In</button> </div> </form> <!-- / Form --> <div class="text-center text-muted"> Don't have an account yet? <a href="javascript:void(0)">Sign Up</a> </div> </div> </div> <!-- / Content --> <!-- Core scripts --> <script src="assets/vendor/libs/popper/popper.js"></script> <script src="assets/vendor/js/bootstrap.js"></script> <script src="assets/vendor/js/sidenav.js"></script> <!-- Libs --> <script src="assets/vendor/libs/perfect-scrollbar/perfect-scrollbar.js"></script> <!-- Demo --> <script src="assets/js/demo.js"></script> </body> </html>
index.html
注意几处修改:
<ul class="sidenav-menu">
<li class="sidenav-item active">
<a href="index.html" class="sidenav-link">
<div>Dashboard 1</div>
</a>
</li>
<li class="sidenav-item">
<a href="/admin" class="sidenav-link">
<div>检测ROLE_ADMIN角色</div>
</a>
</li>
<li class="sidenav-item">
<a href="/user" class="sidenav-link">
<div>检测ROLE_USER角色</div>
</a>
</li>
</ul>
admin和user请求。
<a href="/logout" class="dropdown-item"><i class="ion ion-ios-log-out text-danger"></i> Log Out</a>:logout请求
<!DOCTYPE html> <html lang="en" class="default-style"> <head> <title>Dashboard 1 - Dashboards - Appwork</title> <meta charset="utf-8"> <meta http-equiv="x-ua-compatible" content="IE=edge,chrome=1"> <meta name="description" content=""> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"> <link rel="icon" type="image/x-icon" href="favicon.ico"> <!-- Icon fonts --> <link rel="stylesheet" href="assets/vendor/fonts/fontawesome.css"> <link rel="stylesheet" href="assets/vendor/fonts/ionicons.css"> <link rel="stylesheet" href="assets/vendor/fonts/linearicons.css"> <link rel="stylesheet" href="assets/vendor/fonts/open-iconic.css"> <link rel="stylesheet" href="assets/vendor/fonts/pe-icon-7-stroke.css"> <!-- Core stylesheets --> <link rel="stylesheet" href="assets/vendor/css/rtl/bootstrap.css" class="theme-settings-bootstrap-css"> <link rel="stylesheet" href="assets/vendor/css/rtl/appwork.css" class="theme-settings-appwork-css"> <link rel="stylesheet" href="assets/vendor/css/rtl/theme-corporate.css" class="theme-settings-theme-css"> <link rel="stylesheet" href="assets/vendor/css/rtl/colors.css" class="theme-settings-colors-css"> <link rel="stylesheet" href="assets/vendor/css/rtl/uikit.css"> <link rel="stylesheet" href="assets/css/demo.css"> <!-- Load polyfills --> <script src="assets/vendor/js/polyfills.js"></script> <script src="assets/vendor/js/material-ripple.js"></script> <script src="assets/vendor/js/layout-helpers.js"></script> <!-- Theme settings --> <!-- This file MUST be included after core stylesheets and layout-helpers.js in the <head> section --> <script src="assets/vendor/js/theme-settings.js"></script> <script> window.themeSettings = new ThemeSettings({ cssPath: 'assets/vendor/css/rtl/', themesPath: 'assets/vendor/css/rtl/' }); </script> <!-- Core scripts --> <script src="assets/vendor/js/pace.js"></script> <script src="assets/vendor/libs/jquery-3.2.1.min.js"></script> <!-- Libs --> <link rel="stylesheet" href="assets/vendor/libs/perfect-scrollbar/perfect-scrollbar.css"> </head> <body> <div class="page-loader"> <div class="bg-primary"></div> </div> <!-- Layout wrapper --> <div class="layout-wrapper layout-2"> <div class="layout-inner"> <!-- Layout sidenav --> <div id="layout-sidenav" class="layout-sidenav sidenav sidenav-vertical bg-dark"> <!-- Brand demo (see assets/css/demo/demo.css) --> <div class="app-brand demo"> <span class="app-brand-logo demo bg-primary"> <svg viewBox="0 0 148 80" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><linearGradient id="a" x1="46.49" x2="62.46" y1="53.39" y2="48.2" gradientUnits="userSpaceOnUse"><stop stop-opacity=".25" offset="0"></stop><stop stop-opacity=".1" offset=".3"></stop><stop stop-opacity="0" offset=".9"></stop></linearGradient><linearGradient id="e" x1="76.9" x2="92.64" y1="26.38" y2="31.49" xlink:href="#a"></linearGradient><linearGradient id="d" x1="107.12" x2="122.74" y1="53.41" y2="48.33" xlink:href="#a"></linearGradient></defs><path style="fill: #fff;" transform="translate(-.1)" d="M121.36,0,104.42,45.08,88.71,3.28A5.09,5.09,0,0,0,83.93,0H64.27A5.09,5.09,0,0,0,59.5,3.28L43.79,45.08,26.85,0H.1L29.43,76.74A5.09,5.09,0,0,0,34.19,80H53.39a5.09,5.09,0,0,0,4.77-3.26L74.1,35l16,41.74A5.09,5.09,0,0,0,94.82,80h18.95a5.09,5.09,0,0,0,4.76-3.24L148.1,0Z"></path><path transform="translate(-.1)" d="M52.19,22.73l-8.4,22.35L56.51,78.94a5,5,0,0,0,1.64-2.19l7.34-19.2Z" fill="url(#a)"></path><path transform="translate(-.1)" d="M95.73,22l-7-18.69a5,5,0,0,0-1.64-2.21L74.1,35l8.33,21.79Z" fill="url(#e)"></path><path transform="translate(-.1)" d="M112.73,23l-8.31,22.12,12.66,33.7a5,5,0,0,0,1.45-2l7.3-18.93Z" fill="url(#d)"></path></svg> </span> <a href="index.html" class="app-brand-text demo sidenav-text font-weight-normal ml-2">Appwork</a> <a href="javascript:void(0)" class="layout-sidenav-toggle sidenav-link text-large ml-auto"> <i class="ion ion-md-menu align-middle"></i> </a> </div> <div class="sidenav-divider mt-0"></div> <!-- Links --> <ul class="sidenav-inner py-1"> <!-- Dashboards --> <li class="sidenav-item open active"> <a href="javascript:void(0)" class="sidenav-link sidenav-toggle"><i class="sidenav-icon ion ion-md-speedometer"></i> <div>Dashboards</div> </a> <ul class="sidenav-menu"> <li class="sidenav-item active"> <a href="index.html" class="sidenav-link"> <div>Dashboard 1</div> </a> </li> <li class="sidenav-item"> <a href="/admin" class="sidenav-link"> <div>检测ROLE_ADMIN角色</div> </a> </li> <li class="sidenav-item"> <a href="/user" class="sidenav-link"> <div>检测ROLE_USER角色</div> </a> </li> </ul> </li> <!-- Layouts --> <li class="sidenav-item"> <a href="javascript:void(0)" class="sidenav-link sidenav-toggle"><i class="sidenav-icon ion ion-ios-albums"></i> <div>Layouts</div> </a> <ul class="sidenav-menu"> <li class="sidenav-item"> <a href="layouts_options.html" class="sidenav-link"> <div>Layout options</div> </a> </li> <li class="sidenav-item"> <a href="layouts_helpers.html" class="sidenav-link"> <div>Layout helpers</div> </a> </li> <li class="sidenav-item"> <a href="layouts_layout-1.html" class="sidenav-link"> <div>Layout 1</div> </a> </li> <li class="sidenav-item"> <a href="layouts_layout-1-flex.html" class="sidenav-link"> <div>Layout 1 (Flex)</div> </a> </li> <li class="sidenav-item"> <a href="layouts_layout-2.html" class="sidenav-link"> <div>Layout 2</div> </a> </li> <li class="sidenav-item"> <a href="layouts_layout-2-flex.html" class="sidenav-link"> <div>Layout 2 (Flex)</div> </a> </li> <li class="sidenav-item"> <a href="layouts_without-navbar.html" class="sidenav-link"> <div>Without navbar</div> </a> </li> <li class="sidenav-item"> <a href="layouts_without-navbar-flex.html" class="sidenav-link"> <div>Without navbar (Flex)</div> </a> </li> <li class="sidenav-item"> <a href="layouts_without-sidenav.html" class="sidenav-link"> <div>Without sidenav</div> </a> </li> <li class="sidenav-item"> <a href="layouts_horizontal-sidenav.html" class="sidenav-link"> <div>Horizontal sidenav</div> </a> </li> <li class="sidenav-item"> <a href="layouts_blank.html" class="sidenav-link"> <div>Blank</div> </a> </li> </ul> </li> <li class="sidenav-divider mb-1"></li> <li class="sidenav-header small font-weight-semibold">ELEMENTS</li> <li class="sidenav-item"> <a href="typography.html" class="sidenav-link"><i class="sidenav-icon ion ion-md-quote"></i> <div>Typography</div> </a> </li> <!-- UI elements --> <li class="sidenav-item"> <a href="javascript:void(0)" class="sidenav-link sidenav-toggle"><i class="sidenav-icon ion ion-md-cube"></i> <div>User inteface</div> </a> <ul class="sidenav-menu"> <li class="sidenav-item"> <a href="ui_buttons.html" class="sidenav-link"> <div>Buttons</div> </a> </li> <li class="sidenav-item"> <a href="ui_badges.html" class="sidenav-link"> <div>Badges</div> </a> </li> <li class="sidenav-item"> <a href="ui_button-groups.html" class="sidenav-link"> <div>Button groups</div> </a> </li> <li class="sidenav-item"> <a href="ui_dropdowns.html" class="sidenav-link"> <div>Dropdowns</div> </a> </li> <li class="sidenav-item"> <a href="ui_navs.html" class="sidenav-link"> <div>Navs</div> </a> </li> <li class="sidenav-item"> <a href="ui_pagination.html" class="sidenav-link"> <div>Pagination and breadcrumbs</div> </a> </li> <li class="sidenav-item"> <a href="ui_progress.html" class="sidenav-link"> <div>Progress bars</div> </a> </li> <li class="sidenav-item"> <a href="ui_list-groups.html" class="sidenav-link"> <div>List groups</div> </a> </li> <li class="sidenav-item"> <a href="ui_notifications.html" class="sidenav-link"> <div>Notifications</div> </a> </li> <li class="sidenav-item"> <a href="ui_modals.html" class="sidenav-link"> <div>Modals</div> </a> </li> <li class="sidenav-item"> <a href="ui_tooltips.html" class="sidenav-link"> <div>Tooltips and popovers</div> </a> </li> <li class="sidenav-item"> <a href="ui_thumbnails.html" class="sidenav-link"> <div>Thumbnails</div> </a> </li> <li class="sidenav-item"> <a href="ui_cards.html" class="sidenav-link"> <div>Cards</div> </a> </li> <li class="sidenav-item"> <a href="ui_accordion.html" class="sidenav-link"> <div>Accordion</div> </a> </li> <li class="sidenav-item"> <a href="ui_app-brand.html" class="sidenav-link"> <div>App brand</div> </a> </li> <li class="sidenav-item"> <a href="ui_navbar.html" class="sidenav-link"> <div>Navbar</div> </a> </li> <li class="sidenav-item"> <a href="ui_sidenav.html" class="sidenav-link"> <div>Sidenav</div> </a> </li> <li class="sidenav-item"> <a href="ui_footer.html" class="sidenav-link"> <div>Footer</div> </a> </li> <li class="sidenav-item"> <a href="ui_carousel.html" class="sidenav-link"> <div>Carousel</div> </a> </li> <li class="sidenav-item"> <a href="ui_lightbox.html" class="sidenav-link"> <div>Lightbox</div> </a> </li> <li class="sidenav-item"> <a href="ui_drag-and-drop.html" class="sidenav-link"> <div>Drag&Drop</div> </a> </li> <li class="sidenav-item"> <a href="ui_treeview.html" class="sidenav-link"> <div>Treeview</div> </a> </li> <li class="sidenav-item"> <a href="ui_media-player.html" class="sidenav-link"> <div>Plyr</div> </a> </li> <li class="sidenav-item"> <a href="ui_cropper.html" class="sidenav-link"> <div>Cropper.js</div> </a> </li> <li class="sidenav-item"> <a href="ui_tour.html" class="sidenav-link"> <div>Shepherd tour</div> </a> </li> <li class="sidenav-item"> <a href="ui_fullcalendar.html" class="sidenav-link"> <div>Fullcalendar</div> </a> </li> <li class="sidenav-item"> <a href="ui_spinners.html" class="sidenav-link"> <div>Spinners</div> </a> </li> </ul> </li> <!-- Forms --> <li class="sidenav-item"> <a href="javascript:void(0)" class="sidenav-link sidenav-toggle"><i class="sidenav-icon ion ion-md-switch"></i> <div>Forms</div> </a> <ul class="sidenav-menu"> <li class="sidenav-item"> <a href="forms_layouts.html" class="sidenav-link"> <div>Layouts and elements</div> </a> </li> <li class="sidenav-item"> <a href="forms_controls.html" class="sidenav-link"> <div>Controls</div> </a> </li> <li class="sidenav-item"> <a href="forms_custom-controls.html" class="sidenav-link"> <div>Custom controls</div> </a> </li> <li class="sidenav-item"> <a href="forms_input-groups.html" class="sidenav-link"> <div>Input groups</div> </a> </li> <li class="sidenav-item"> <a href="forms_switchers.html" class="sidenav-link"> <div>Switchers</div> </a> </li> <li class="sidenav-item"> <a href="forms_sliders.html" class="sidenav-link"> <div>Sliders</div> </a> </li> <li class="sidenav-item"> <a href="forms_selects.html" class="sidenav-link"> <div>Selects and tags</div> </a> </li> <li class="sidenav-item"> <a href="forms_pickers.html" class="sidenav-link"> <div>Pickers</div> </a> </li> <li class="sidenav-item"> <a href="forms_editors.html" class="sidenav-link"> <div>Editors</div> </a> </li> <li class="sidenav-item"> <a href="forms_file-upload.html" class="sidenav-link"> <div>File upload</div> </a> </li> <li class="sidenav-item"> <a href="forms_validation.html" class="sidenav-link"> <div>jQuery Validation</div> </a> </li> <li class="sidenav-item"> <a href="forms_wizard.html" class="sidenav-link"> <div>SmartWizard</div> </a> </li> <li class="sidenav-item"> <a href="forms_typeahead.html" class="sidenav-link"> <div>Typeahead</div> </a> </li> <li class="sidenav-item"> <a href="forms_dual-listbox.html" class="sidenav-link"> <div>Bootstrap Dual Listbox</div> </a> </li> <li class="sidenav-item"> <a href="forms_extras.html" class="sidenav-link"> <div>Extras</div> </a> </li> </ul> </li> <!-- Tables --> <li class="sidenav-item"> <a href="javascript:void(0)" class="sidenav-link sidenav-toggle"><i class="sidenav-icon ion ion-md-grid"></i> <div>Tables</div> </a> <ul class="sidenav-menu"> <li class="sidenav-item"> <a href="tables_bootstrap.html" class="sidenav-link"> <div>Bootstrap</div> </a> </li> <li class="sidenav-item"> <a href="tables_datatables.html" class="sidenav-link"> <div>DataTables</div> </a> </li> <li class="sidenav-item"> <a href="tables_bootstrap-table.html" class="sidenav-link"> <div>Bootstrap table</div> </a> </li> <li class="sidenav-item"> <a href="tables_bootstrap-sortable.html" class="sidenav-link"> <div>Bootstrap Sortable</div> </a> </li> </ul> </li> <!-- Charts --> <li class="sidenav-item"> <a href="javascript:void(0)" class="sidenav-link sidenav-toggle"><i class="sidenav-icon ion ion-md-pie"></i> <div>Charts</div> </a> <ul class="sidenav-menu"> <li class="sidenav-item"> <a href="charts_gmaps.html" class="sidenav-link"> <div>GMaps</div> </a> </li> <li class="sidenav-item"> <a href="charts_mapael.html" class="sidenav-link"> <div>Mapael</div> </a> </li> <li class="sidenav-item"> <a href="charts_flot.html" class="sidenav-link"> <div>Flot.js</div> </a> </li> <li class="sidenav-item"> <a href="charts_c3.html" class="sidenav-link"> <div>C3.js</div> </a> </li> <li class="sidenav-item"> <a href="charts_chartist.html" class="sidenav-link"> <div>Chartist</div> </a> </li> <li class="sidenav-item"> <a href="charts_chartjs.html" class="sidenav-link"> <div>Chart.js</div> </a> </li> <li class="sidenav-item"> <a href="charts_morrisjs.html" class="sidenav-link"> <div>Morris.js</div> </a> </li> <li class="sidenav-item"> <a href="charts_sparkline.html" class="sidenav-link"> <div>Sparkline</div> </a> </li> </ul> </li> <!-- Icons --> <li class="sidenav-item"> <a href="javascript:void(0)" class="sidenav-link sidenav-toggle"><i class="sidenav-icon ion ion-ios-heart"></i> <div>Icons</div> </a> <ul class="sidenav-menu"> <li class="sidenav-item"> <a href="icons_font-awesome.html" class="sidenav-link"> <div>Font Awesome 5</div> </a> </li> <li class="sidenav-item"> <a href="icons_ionicons.html" class="sidenav-link"> <div>Ionicons</div> </a> </li> <li class="sidenav-item"> <a href="icons_linearicons.html" class="sidenav-link"> <div>Linearicons</div> </a> </li> <li class="sidenav-item"> <a href="icons_openiconic.html" class="sidenav-link"> <div>Open Iconic</div> </a> </li> <li class="sidenav-item"> <a href="icons_stroke7.html" class="sidenav-link"> <div>Stroke Icons 7</div> </a> </li> </ul> </li> <!-- Miscellaneous --> <li class="sidenav-item"> <a href="javascript:void(0)" class="sidenav-link sidenav-toggle"><i class="sidenav-icon ion ion-ios-flask"></i> <div>Miscellaneous</div> </a> <ul class="sidenav-menu"> <li class="sidenav-item"> <a href="misc_brand-colors.html" class="sidenav-link"> <div>Brand colors</div> </a> </li> <li class="sidenav-item"> <a href="misc_masonry.html" class="sidenav-link"> <div>Masonry</div> </a> </li> <li class="sidenav-item"> <a href="misc_spinkit.html" class="sidenav-link"> <div>SpinKit</div> </a> </li> <li class="sidenav-item"> <a href="misc_ladda.html" class="sidenav-link"> <div>Ladda</div> </a> </li> <li class="sidenav-item"> <a href="misc_vegasjs.html" class="sidenav-link"> <div>Vegas.js</div> </a> </li> <li class="sidenav-item"> <a href="misc_numeraljs.html" class="sidenav-link"> <div>Numeral.js</div> </a> </li> <li class="sidenav-item"> <a href="misc_blockui.html" class="sidenav-link"> <div>BlockUI</div> </a> </li> <li class="sidenav-item"> <a href="misc_idle-timer.html" class="sidenav-link"> <div>Idle Timer</div> </a> </li> <li class="sidenav-item"> <a href="misc_perfect-scrollbar.html" class="sidenav-link"> <div>Perfect Scrollbar</div> </a> </li> <li class="sidenav-item"> <a href="misc_clipboardjs.html" class="sidenav-link"> <div>Clipboard.js</div> </a> </li> </ul> </li> <li class="sidenav-divider mb-1"></li> <li class="sidenav-header small font-weight-semibold">EXTRAS</li> <!-- Pages --> <li class="sidenav-item"> <a href="javascript:void(0)" class="sidenav-link sidenav-toggle"> <i class="sidenav-icon ion ion-md-document"></i> <div>Pages</div> <div class="pl-1 ml-auto"> <div class="badge badge-primary">59</div> </div> </a> <ul class="sidenav-menu"> <li class="sidenav-item"> <a href="javascript:void(0)" class="sidenav-link sidenav-toggle"> <div>Articles</div> </a> <ul class="sidenav-menu"> <li class="sidenav-item"> <a href="pages_articles_list.html" class="sidenav-link"> <div>List</div> </a> </li> <li class="sidenav-item"> <a href="pages_articles_edit.html" class="sidenav-link"> <div>Edit</div> </a> </li> </ul> </li> <li class="sidenav-item"> <a href="javascript:void(0)" class="sidenav-link sidenav-toggle"> <div>Authentication</div> </a> <ul class="sidenav-menu"> <li class="sidenav-item"> <a href="pages_authentication_login-v1.html" class="sidenav-link"> <div>Login v1</div> </a> </li> <li class="sidenav-item"> <a href="pages_authentication_register-v1.html" class="sidenav-link"> <div>Register v1</div> </a> </li> <li class="sidenav-item"> <a href="pages_authentication_login-v2.html" class="sidenav-link"> <div>Login v2</div> </a> </li> <li class="sidenav-item"> <a href="pages_authentication_register-v2.html" class="sidenav-link"> <div>Register v2</div> </a> </li> <li class="sidenav-item"> <a href="pages_authentication_login-v3.html" class="sidenav-link"> <div>Login v3</div> </a> </li> <li class="sidenav-item"> <a href="pages_authentication_register-v3.html" class="sidenav-link"> <div>Register v3</div> </a> </li> <li class="sidenav-item"> <a href="pages_authentication_login-and-register.html" class="sidenav-link"> <div>Login + Register</div> </a> </li> <li class="sidenav-item"> <a href="pages_authentication_lock-screen-v1.html" class="sidenav-link"> <div>Lock screen v1</div> </a> </li> <li class="sidenav-item"> <a href="pages_authentication_lock-screen-v2.html" class="sidenav-link"> <div>Lock screen v2</div> </a> </li> <li class="sidenav-item"> <a href="pages_authentication_password-reset.html" class="sidenav-link"> <div>Password reset</div> </a> </li> <li class="sidenav-item"> <a href="pages_authentication_email-confirm.html" class="sidenav-link"> <div>Email confirm</div> </a> </li> </ul> </li> <li class="sidenav-item"> <a href="javascript:void(0)" class="sidenav-link sidenav-toggle"> <div>Education</div> </a> <ul class="sidenav-menu"> <li class="sidenav-item"> <a href="pages_education_courses-v1.html" class="sidenav-link"> <div>Courses v1</div> </a> </li> <li class="sidenav-item"> <a href="pages_education_courses-v2.html" class="sidenav-link"> <div>Courses v2</div> </a> </li> </ul> </li> <li class="sidenav-item"> <a href="javascript:void(0)" class="sidenav-link sidenav-toggle"> <div>E-commerce</div> </a> <ul class="sidenav-menu"> <li class="sidenav-item"> <a href="pages_e-commerce_product-list.html" class="sidenav-link"> <div>Product list</div> </a> </li> <li class="sidenav-item"> <a href="pages_e-commerce_product-item.html" class="sidenav-link"> <div>Product item</div> </a> </li> <li class="sidenav-item"> <a href="pages_e-commerce_product-edit.html" class="sidenav-link"> <div>Product edit</div> </a> </li> <li class="sidenav-item"> <a href="pages_e-commerce_order-list.html" class="sidenav-link"> <div>Order list</div> </a> </li> <li class="sidenav-item"> <a href="pages_e-commerce_order-detail.html" class="sidenav-link"> <div>Order detail</div> </a> </li> </ul> </li> <li class="sidenav-item"> <a href="javascript:void(0)" class="sidenav-link sidenav-toggle"> <div>Forums</div> </a> <ul class="sidenav-menu"> <li class="sidenav-item"> <a href="pages_forums_list.html" class="sidenav-link"> <div>List</div> </a> </li> <li class="sidenav-item"> <a href="pages_forums_threads.html" class="sidenav-link"> <div>Threads</div> </a> </li> <li class="sidenav-item"> <a href="pages_forums_discussion.html" class="sidenav-link"> <div>Discussion</div> </a> </li> </ul> </li> <li class="sidenav-item"> <a href="javascript:void(0)" class="sidenav-link sidenav-toggle"> <div>Messages v1</div> </a> <ul class="sidenav-menu"> <li class="sidenav-item"> <a href="pages_messages_v1_list.html" class="sidenav-link"> <div>List</div> </a> </li> <li class="sidenav-item"> <a href="pages_messages_v1_item.html" class="sidenav-link"> <div>Item</div> </a> </li> <li class="sidenav-item"> <a href="pages_messages_v1_compose.html" class="sidenav-link"> <div>Compose</div> </a> </li> </ul> </li> <li class="sidenav-item"> <a href="javascript:void(0)" class="sidenav-link sidenav-toggle"> <div>Messages v2</div> </a> <ul class="sidenav-menu"> <li class="sidenav-item"> <a href="pages_messages_v2_list.html" class="sidenav-link"> <div>List</div> </a> </li> <li class="sidenav-item"> <a href="pages_messages_v2_item.html" class="sidenav-link"> <div>Item</div> </a> </li> <li class="sidenav-item"> <a href="pages_messages_v2_compose.html" class="sidenav-link"> <div>Compose</div> </a> </li> </ul> </li> <li class="sidenav-item"> <a href="javascript:void(0)" class="sidenav-link sidenav-toggle"> <div>Messages v3</div> </a> <ul class="sidenav-menu"> <li class="sidenav-item"> <a href="pages_messages_v3_list.html" class="sidenav-link"> <div>List</div> </a> </li> <li class="sidenav-item"> <a href="pages_messages_v3_item.html" class="sidenav-link"> <div>Item</div> </a> </li> <li class="sidenav-item"> <a href="pages_messages_v3_compose.html" class="sidenav-link"> <div>Compose</div> </a> </li> </ul> </li> <li class="sidenav-item"> <a href="javascript:void(0)" class="sidenav-link sidenav-toggle"> <div>Projects</div> </a> <ul class="sidenav-menu"> <li class="sidenav-item"> <a href="pages_projects_list.html" class="sidenav-link"> <div>List</div> </a> </li> <li class="sidenav-item"> <a href="pages_projects_item.html" class="sidenav-link"> <div>Item</div> </a> </li> </ul> </li> <li class="sidenav-item"> <a href="javascript:void(0)" class="sidenav-link sidenav-toggle"> <div>Tickets</div> </a> <ul class="sidenav-menu"> <li class="sidenav-item"> <a href="pages_tickets_list.html" class="sidenav-link"> <div>List</div> </a> </li> <li class="sidenav-item"> <a href="pages_tickets_edit.html" class="sidenav-link"> <div>Edit</div> </a> </li> </ul> </li> <li class="sidenav-item"> <a href="javascript:void(0)" class="sidenav-link sidenav-toggle"> <div>Users</div> </a> <ul class="sidenav-menu"> <li class="sidenav-item"> <a href="pages_users_list.html" class="sidenav-link"> <div>List</div> </a> </li> <li class="sidenav-item"> <a href="pages_users_view.html" class="sidenav-link"> <div>View</div> </a> </li> <li class="sidenav-item"> <a href="pages_users_edit.html" class="sidenav-link"> <div>Edit</div> </a> </li> </ul> </li> <li class="sidenav-item"> <a href="pages_account-settings.html" class="sidenav-link"> <div>Account settings</div> </a> </li> <li class="sidenav-item"> <a href="pages_chat.html" class="sidenav-link"> <div>Chat</div> </a> </li> <li class="sidenav-item"> <a href="pages_clients.html" class="sidenav-link"> <div>Clients</div> </a> </li> <li class="sidenav-item"> <a href="pages_contacts.html" class="sidenav-link"> <div>Contacts</div> </a> </li> <li class="sidenav-item"> <a href="pages_faq.html" class="sidenav-link"> <div>FAQ</div> </a> </li> <li class="sidenav-item"> <a href="pages_file-manager.html" class="sidenav-link"> <div>File manager</div> </a> </li> <li class="sidenav-item"> <a href="pages_gallery.html" class="sidenav-link"> <div>Gallery</div> </a> </li> <li class="sidenav-item"> <a href="pages_help-center.html" class="sidenav-link"> <div>Help center</div> </a> </li> <li class="sidenav-item"> <a href="pages_invoice.html" class="sidenav-link"> <div>Invoice</div> </a> </li> <li class="sidenav-item"> <a href="pages_kanban-board.html" class="sidenav-link"> <div>Kanban board</div> </a> </li> <li class="sidenav-item"> <a href="pages_pricing.html" class="sidenav-link"> <div>Pricing</div> </a> </li> <li class="sidenav-item"> <a href="pages_profile-v1.html" class="sidenav-link"> <div>Profile v1</div> </a> </li> <li class="sidenav-item"> <a href="pages_profile-v2.html" class="sidenav-link"> <div>Profile v2</div> </a> </li> <li class="sidenav-item"> <a href="pages_search-results.html" class="sidenav-link"> <div>Search results</div> </a> </li> <li class="sidenav-item"> <a href="pages_task-list.html" class="sidenav-link"> <div>Task list</div> </a> </li> <li class="sidenav-item"> <a href="pages_teams.html" class="sidenav-link"> <div>Teams</div> </a> </li> <li class="sidenav-item"> <a href="pages_vacancies.html" class="sidenav-link"> <div>Vacancies</div> </a> </li> <li class="sidenav-item"> <a href="pages_voting.html" class="sidenav-link"> <div>Voting</div> </a> </li> </ul> </li> <li class="sidenav-item"> <a href="javascript:void(0)" class="sidenav-link sidenav-toggle"><i class="sidenav-icon ion ion-logo-buffer"></i> <div>Complete UI</div> </a> <ul class="sidenav-menu"> <li class="sidenav-item"> <a target="_blank" href="complete-ui_base.html" class="sidenav-link"> <div>Base</div> </a> </li> <li class="sidenav-item"> <a target="_blank" href="complete-ui_plugins.html" class="sidenav-link"> <div>Plugins</div> </a> </li> <li class="sidenav-item"> <a target="_blank" href="complete-ui_charts.html" class="sidenav-link"> <div>Charts</div> </a> </li> </ul> </li> </ul> </div> <!-- / Layout sidenav --> <!-- Layout container --> <div class="layout-container"> <!-- Layout navbar --> <nav class="layout-navbar navbar navbar-expand-lg align-items-lg-center bg-white container-p-x" id="layout-navbar"> <!-- Brand demo (see assets/css/demo/demo.css) --> <a href="index.html" class="navbar-brand app-brand demo d-lg-none py-0 mr-4"> <span class="app-brand-logo demo bg-primary"> <svg viewBox="0 0 148 80" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><linearGradient id="a" x1="46.49" x2="62.46" y1="53.39" y2="48.2" gradientUnits="userSpaceOnUse"><stop stop-opacity=".25" offset="0"></stop><stop stop-opacity=".1" offset=".3"></stop><stop stop-opacity="0" offset=".9"></stop></linearGradient><linearGradient id="e" x1="76.9" x2="92.64" y1="26.38" y2="31.49" xlink:href="#a"></linearGradient><linearGradient id="d" x1="107.12" x2="122.74" y1="53.41" y2="48.33" xlink:href="#a"></linearGradient></defs><path style="fill: #fff;" transform="translate(-.1)" d="M121.36,0,104.42,45.08,88.71,3.28A5.09,5.09,0,0,0,83.93,0H64.27A5.09,5.09,0,0,0,59.5,3.28L43.79,45.08,26.85,0H.1L29.43,76.74A5.09,5.09,0,0,0,34.19,80H53.39a5.09,5.09,0,0,0,4.77-3.26L74.1,35l16,41.74A5.09,5.09,0,0,0,94.82,80h18.95a5.09,5.09,0,0,0,4.76-3.24L148.1,0Z"></path><path transform="translate(-.1)" d="M52.19,22.73l-8.4,22.35L56.51,78.94a5,5,0,0,0,1.64-2.19l7.34-19.2Z" fill="url(#a)"></path><path transform="translate(-.1)" d="M95.73,22l-7-18.69a5,5,0,0,0-1.64-2.21L74.1,35l8.33,21.79Z" fill="url(#e)"></path><path transform="translate(-.1)" d="M112.73,23l-8.31,22.12,12.66,33.7a5,5,0,0,0,1.45-2l7.3-18.93Z" fill="url(#d)"></path></svg> </span> <span class="app-brand-text demo font-weight-normal ml-2">Appwork</span> </a> <!-- Sidenav toggle (see assets/css/demo/demo.css) --> <div class="layout-sidenav-toggle navbar-nav d-lg-none align-items-lg-center mr-auto"> <a class="nav-item nav-link px-0 mr-lg-4" href="javascript:void(0)"> <i class="ion ion-md-menu text-large align-middle"></i> </a> </div> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#layout-navbar-collapse"> <span class="navbar-toggler-icon"></span> </button> <div class="navbar-collapse collapse" id="layout-navbar-collapse"> <!-- Divider --> <hr class="d-lg-none w-100 my-2"> <div class="navbar-nav align-items-lg-center"> <!-- Search --> <label class="nav-item navbar-text navbar-search-box p-0 active"> <i class="ion ion-ios-search navbar-icon align-middle"></i> <span class="navbar-search-input pl-2"> <input type="text" class="form-control navbar-text mx-2" placeholder="Search..." style="width:200px"> </span> </label> </div> <div class="navbar-nav align-items-lg-center ml-auto"> <div class="demo-navbar-notifications nav-item dropdown mr-lg-3"> <a class="nav-link dropdown-toggle hide-arrow" href="#" data-toggle="dropdown"> <i class="ion ion-md-notifications-outline navbar-icon align-middle"></i> <span class="badge badge-primary badge-dot indicator"></span> <span class="d-lg-none align-middle"> Notifications</span> </a> <div class="dropdown-menu dropdown-menu-right"> <div class="bg-primary text-center text-white font-weight-bold p-3"> 4 New Notifications </div> <div class="list-group list-group-flush"> <a href="javascript:void(0)" class="list-group-item list-group-item-action media d-flex align-items-center"> <div class="ui-icon ui-icon-sm ion ion-md-home bg-secondary border-0 text-white"></div> <div class="media-body line-height-condenced ml-3"> <div class="text-body">Login from 192.168.1.1</div> <div class="text-light small mt-1"> Aliquam ex eros, imperdiet vulputate hendrerit et. </div> <div class="text-light small mt-1">12h ago</div> </div> </a> <a href="javascript:void(0)" class="list-group-item list-group-item-action media d-flex align-items-center"> <div class="ui-icon ui-icon-sm ion ion-md-person-add bg-info border-0 text-white"></div> <div class="media-body line-height-condenced ml-3"> <div class="text-body">You have <strong>4</strong> new followers</div> <div class="text-light small mt-1"> Phasellus nunc nisl, posuere cursus pretium nec, dictum vehicula tellus. </div> </div> </a> <a href="javascript:void(0)" class="list-group-item list-group-item-action media d-flex align-items-center"> <div class="ui-icon ui-icon-sm ion ion-md-power bg-danger border-0 text-white"></div> <div class="media-body line-height-condenced ml-3"> <div class="text-body">Server restarted</div> <div class="text-light small mt-1"> 19h ago </div> </div> </a> <a href="javascript:void(0)" class="list-group-item list-group-item-action media d-flex align-items-center"> <div class="ui-icon ui-icon-sm ion ion-md-warning bg-warning border-0 text-body"></div> <div class="media-body line-height-condenced ml-3"> <div class="text-body">99% server load</div> <div class="text-light small mt-1"> Etiam nec fringilla magna. Donec mi metus. </div> <div class="text-light small mt-1"> 20h ago </div> </div> </a> </div> <a href="javascript:void(0)" class="d-block text-center text-light small p-2 my-1">Show all notifications</a> </div> </div> <div class="demo-navbar-messages nav-item dropdown mr-lg-3"> <a class="nav-link dropdown-toggle hide-arrow" href="#" data-toggle="dropdown"> <i class="ion ion-ios-mail navbar-icon align-middle"></i> <span class="badge badge-primary badge-dot indicator"></span> <span class="d-lg-none align-middle"> Messages</span> </a> <div class="dropdown-menu dropdown-menu-right"> <div class="bg-primary text-center text-white font-weight-bold p-3"> 4 New Messages </div> <div class="list-group list-group-flush"> <a href="javascript:void(0)" class="list-group-item list-group-item-action media d-flex align-items-center"> <img src="assets/img/avatars/6-small.png" class="d-block ui-w-40 rounded-circle" alt> <div class="media-body ml-3"> <div class="text-body line-height-condenced">Sit meis deleniti eu, pri vidit meliore docendi ut.</div> <div class="text-light small mt-1"> Mae Gibson · 58m ago </div> </div> </a> <a href="javascript:void(0)" class="list-group-item list-group-item-action media d-flex align-items-center"> <img src="assets/img/avatars/4-small.png" class="d-block ui-w-40 rounded-circle" alt> <div class="media-body ml-3"> <div class="text-body line-height-condenced">Mea et legere fuisset, ius amet purto luptatum te.</div> <div class="text-light small mt-1"> Kenneth Frazier · 1h ago </div> </div> </a> <a href="javascript:void(0)" class="list-group-item list-group-item-action media d-flex align-items-center"> <img src="assets/img/avatars/5-small.png" class="d-block ui-w-40 rounded-circle" alt> <div class="media-body ml-3"> <div class="text-body line-height-condenced">Sit meis deleniti eu, pri vidit meliore docendi ut.</div> <div class="text-light small mt-1"> Nelle Maxwell · 2h ago </div> </div> </a> <a href="javascript:void(0)" class="list-group-item list-group-item-action media d-flex align-items-center"> <img src="assets/img/avatars/11-small.png" class="d-block ui-w-40 rounded-circle" alt> <div class="media-body ml-3"> <div class="text-body line-height-condenced">Lorem ipsum dolor sit amet, vis erat denique in, dicunt prodesset te vix.</div> <div class="text-light small mt-1"> Belle Ross · 5h ago </div> </div> </a> </div> <a href="javascript:void(0)" class="d-block text-center text-light small p-2 my-1">Show all messages</a> </div> </div> <!-- Divider --> <div class="nav-item d-none d-lg-block text-big font-weight-light line-height-1 opacity-25 mr-3 ml-1">|</div> <div class="demo-navbar-user nav-item dropdown"> <a class="nav-link dropdown-toggle" href="#" data-toggle="dropdown"> <span class="d-inline-flex flex-lg-row-reverse align-items-center align-middle"> <img src="assets/img/avatars/1.png" alt class="d-block ui-w-30 rounded-circle"> <span class="px-1 mr-lg-2 ml-2 ml-lg-0">Mike Greene</span> </span> </a> <div class="dropdown-menu dropdown-menu-right"> <a href="javascript:void(0)" class="dropdown-item"><i class="ion ion-ios-person text-lightest"></i> My profile</a> <a href="javascript:void(0)" class="dropdown-item"><i class="ion ion-ios-mail text-lightest"></i> Messages</a> <a href="javascript:void(0)" class="dropdown-item"><i class="ion ion-md-settings text-lightest"></i> Account settings</a> <div class="dropdown-divider"></div> <a href="/logout" class="dropdown-item"><i class="ion ion-ios-log-out text-danger"></i> Log Out</a> </div> </div> </div> </div> </nav> <!-- / Layout navbar --> <!-- Layout content --> <div class="layout-content"> <!-- Content --> <div class="container-fluid flex-grow-1 container-p-y"> <h4 class="font-weight-bold py-3 mb-4"> Dashboard <div class="text-muted text-tiny mt-1"><small class="font-weight-normal">Today is Tuesday, 8 February 2018</small></div> </h4> <!-- Counters --> <div class="row"> <div class="col-sm-6 col-xl-3"> <div class="card mb-4"> <div class="card-body"> <div class="d-flex align-items-center"> <div class="lnr lnr-cart display-4 text-success"></div> <div class="ml-3"> <div class="text-muted small">Monthly sales</div> <div class="text-large">2362</div> </div> </div> </div> </div> </div> <div class="col-sm-6 col-xl-3"> <div class="card mb-4"> <div class="card-body"> <div class="d-flex align-items-center"> <div class="lnr lnr-earth display-4 text-info"></div> <div class="ml-3"> <div class="text-muted small">Monthly visits</div> <div class="text-large">687,123</div> </div> </div> </div> </div> </div> <div class="col-sm-6 col-xl-3"> <div class="card mb-4"> <div class="card-body"> <div class="d-flex align-items-center"> <div class="lnr lnr-gift display-4 text-danger"></div> <div class="ml-3"> <div class="text-muted small">Products</div> <div class="text-large">985</div> </div> </div> </div> </div> </div> <div class="col-sm-6 col-xl-3"> <div class="card mb-4"> <div class="card-body"> <div class="d-flex align-items-center"> <div class="lnr lnr-users display-4 text-warning"></div> <div class="ml-3"> <div class="text-muted small">Users</div> <div class="text-large">105,652</div> </div> </div> </div> </div> </div> </div> <!-- / Counters --> <!-- Statistics --> <div class="card mb-4"> <h6 class="card-header with-elements"> <div class="card-header-title">Statistics</div> <div class="card-header-elements ml-auto"> <label class="text m-0"> <span class="text-light text-tiny font-weight-semibold align-middle"> SHOW STATS </span> <span class="switcher switcher-sm d-inline-block align-middle mr-0 ml-2"> <input type="checkbox" class="switcher-input" checked> <span class="switcher-indicator"> <span class="switcher-yes"></span> <span class="switcher-no"></span> </span> </span> </label> </div> </h6> <div class="row no-gutters row-bordered"> <div class="col-md-8 col-lg-12 col-xl-8"> <div class="card-body"> <div style="height: 210px;"> <canvas id="statistics-chart-1"></canvas> </div> </div> </div> <div class="col-md-4 col-lg-12 col-xl-4"> <div class="card-body"> <!-- Numbers --> <div class="row"> <div class="col-6 col-xl-5 text-muted mb-3">Total sales</div> <div class="col-6 col-xl-7 mb-3"> <span class="text-big">10,332</span> <sup class="text-success">+12%</sup> </div> <div class="col-6 col-xl-5 text-muted mb-3">Income amount</div> <div class="col-6 col-xl-7 mb-3"> <span class="text-big">$1,534</span> <sup class="text-danger">-5%</sup> </div> <div class="col-6 col-xl-5 text-muted mb-3">Total budget</div> <div class="col-6 col-xl-7 mb-3"> <span class="text-big">$10,534</span> <sup class="text-success">+12%</sup> </div> <div class="col-6 col-xl-5 text-muted mb-3">Page views</div> <div class="col-6 col-xl-7 mb-3"> <span class="text-big">21,332</span> <sup class="text-danger">-12%</sup> </div> <div class="col-6 col-xl-5 text-muted mb-3">Completed tasks</div> <div class="col-6 col-xl-7 mb-3"> <span class="text-big">12</span> <sup class="text-success">+12%</sup> </div> </div> <!-- / Numbers --> </div> </div> </div> </div> <!-- / Statistics --> <div class="row"> <!-- Charts --> <div class="col-sm-6 col-xl-4"> <div class="card mb-4"> <h6 class="card-header with-elements border-0 pr-0 pb-0"> <div class="card-header-title">Sales</div> <div class="card-header-elements ml-auto"> <div class="btn-group mr-3"> <button type="button" class="btn btn-sm btn-default icon-btn borderless rounded-pill md-btn-flat dropdown-toggle hide-arrow" data-toggle="dropdown"> <i class="ion ion-ios-more"></i> </button> <div class="dropdown-menu dropdown-menu-right" id="sales-dropdown-menu"> <a class="dropdown-item" href="javascript:void(0)">Action 1</a> <a class="dropdown-item" href="javascript:void(0)">Action 2</a> </div> </div> </div> </h6> <div class="mt-3"> <div style="height:100px;"> <canvas id="statistics-chart-2"></canvas> </div> </div> <div class="card-footer text-center py-2"> <div class="row"> <div class="col"> <div class="text-muted small">Target</div> <strong class="text-big">500</strong> </div> <div class="col"> <div class="text-muted small">Current</div> <strong class="text-big">421</strong> </div> </div> </div> </div> </div> <div class="col-sm-6 col-xl-4"> <div class="card mb-4"> <div class="card-body"> <div class="float-right text-success"> <small class="ion ion-md-arrow-round-up text-tiny"></small> 12% </div> <div class="text-muted small">Total revenue</div> <div class="text-xlarge">$1,534</div> </div> <div class="px-2"> <div class="w-100" style="height: 117px;"> <canvas id="statistics-chart-3"></canvas> </div> </div> </div> </div> <div class="col-sm-6 col-xl-4"> <div class="card mb-4"> <div class="card-body pb-0"> <div class="text-right small mb-4">Aug 2017 - Feb 2018</div> <div class="my-3" style="height: 86px;"> <canvas id="statistics-chart-4"></canvas> </div> </div> <div class="card-footer"> <button type="button" class="btn btn-xs btn-outline-primary icon-btn float-right"><i class="ion ion-md-sync"></i></button> Unique visitors </div> </div> </div> <div class="col-sm-6 col-xl-3"> <div class="card mb-4"> <h6 class="card-header bg-success text-white"> <i class="ion ion-md-cash"></i> Revenue </h6> <div class="bg-success text-white"> <div class="d-flex align-items-center position-relative mt-4" style="height:140px;"> <div class="w-100 position-absolute" style="height:140px;top:0;"> <canvas id="statistics-chart-5"></canvas> </div> <div class="w-100 text-center text-xlarge">85</div> </div> <div class="text-center mt-3 mb-4"> Sales today </div> </div> <div class="card-footer border-0 text-center py-3"> <div class="row"> <div class="col"> <div class="text-muted small mb-1">Target</div> <strong class="text-big">$1225</strong> </div> <div class="col"> <div class="text-muted small mb-1">Current</div> <strong class="text-big">$654</strong> </div> </div> </div> </div> </div> <!-- / Charts --> <div class="col-xl-9"> <div class="row"> <div class="col-md-6"> <!-- Tasks --> <div class="card mb-4"> <h6 class="card-header with-elements"> <div class="card-header-title">Tasks</div> <div class="card-header-elements ml-auto"> <button type="button" class="btn btn-default btn-xs md-btn-flat">Show more</button> </div> </h6> <div style="height: 234px" id="tasks-inner"> <div class="card-body"> <p class="text-muted small">Today</p> <div class="custom-controls-stacked"> <label class="ui-todo-item custom-control custom-checkbox"> <input type="checkbox" class="custom-control-input"> <span class="custom-control-label">Buy products</span> <span class="ui-todo-badge badge badge-outline-default font-weight-normal ml-2">58 mins left</span> </label> <label class="ui-todo-item custom-control custom-checkbox"> <input type="checkbox" class="custom-control-input"> <span class="custom-control-label">Reply to emails</span> </label> <label class="ui-todo-item custom-control custom-checkbox"> <input type="checkbox" class="custom-control-input"> <span class="custom-control-label">Write blog post</span> <span class="ui-todo-badge badge badge-outline-default font-weight-normal ml-2">20 hours left</span> </label> <label class="ui-todo-item custom-control custom-checkbox"> <input type="checkbox" class="custom-control-input" checked> <span class="custom-control-label">Wash my car</span> </label> </div> </div> <hr class="m-0"> <div class="card-body"> <p class="text-muted small">Tomorrow</p> <div class="custom-controls-stacked"> <label class="ui-todo-item custom-control custom-checkbox"> <input type="checkbox" class="custom-control-input"> <span class="custom-control-label">Buy antivirus</span> </label> <label class="ui-todo-item custom-control custom-checkbox"> <input type="checkbox" class="custom-control-input"> <span class="custom-control-label">Jane's Happy Birthday</span> </label> <label class="ui-todo-item custom-control custom-checkbox"> <input type="checkbox" class="custom-control-input"> <span class="custom-control-label">Call mom</span> </label> </div> </div> </div> <div class="card-footer"> <div class="input-group"> <input type="text" class="form-control" placeholder="Type your task"> <div class="input-group-append"> <button type="button" class="btn btn-primary">Add</button> </div> </div> </div> </div> <!-- / Tasks --> </div> <div class="col-md-6"> <!-- Team ToDo --> <div class="card mb-4"> <h6 class="card-header with-elements"> <div class="card-header-title">Team TODO</div> <div class="card-header-elements ml-auto"> <button type="button" class="btn btn-default btn-xs md-btn-flat">Show more</button> </div> </h6> <div style="height: 300px" id="team-todo-inner"> <div class="card-body"> <div class="rounded ui-bordered p-3 mb-3"> Lorem ipsum dolor sit amet, vis erat denique in, dicunt prodesset te vix. <div class="media align-items-center mt-3"> <img src="assets/img/avatars/12-small.png" class="d-block ui-w-30 rounded-circle" alt> <div class="media-body ml-2">Arthur Duncan</div> <div class="text-muted small text-nowrap">02/08/2018</div> </div> </div> <div class="rounded ui-bordered p-3 mb-3"> Sit meis deleniti eu, pri vidit meliore docendi ut. <div class="media align-items-center mt-3"> <img src="assets/img/avatars/11-small.png" class="d-block ui-w-30 rounded-circle" alt> <div class="media-body ml-2">Belle Ross</div> <div class="text-muted small text-nowrap">02/06/2018</div> </div> </div> <div class="rounded ui-bordered p-3"> Cum ea graeci tractatos. <div class="media align-items-center mt-3"> <img src="assets/img/avatars/10-small.png" class="d-block ui-w-30 rounded-circle" alt> <div class="media-body ml-2">Wayne Morgan</div> <div class="text-muted small text-nowrap">02/04/2018</div> </div> </div> </div> </div> </div> <!-- / Team ToDo --> </div> </div> </div> <div class="col-md-8"> <!-- Sale stats --> <div class="card mb-4"> <h6 class="card-header with-elements"> <div class="card-header-title">Sale stats</div> <div class="card-header-elements ml-auto"> <button type="button" class="btn btn-default btn-xs md-btn-flat">Show more</button> </div> </h6> <div class="table-responsive"> <table class="table card-table"> <thead> <tr> <th>Date</th> <th>Sales</th> <th>Cancelled</th> <th>Delivered</th> </tr> </thead> <tbody> <tr> <td>02/08/2018</td> <td>12</td> <td>1</td> <td>5</td> </tr> <tr> <td>02/07/2018</td> <td>16</td> <td>2</td> <td>8</td> </tr> <tr> <td>02/06/2018</td> <td>5</td> <td>0</td> <td>2</td> </tr> <tr> <td>02/05/2018</td> <td>21</td> <td>1</td> <td>10</td> </tr> </tbody> </table> </div> </div> <!-- / Sale stats --> </div> <div class="col-md-4"> <!-- Type gadgets chart --> <div class="card mb-4"> <h6 class="card-header with-elements"> <div class="card-header-title">Type gadgets</div> <div class="card-header-elements ml-auto"> <button type="button" class="btn btn-outline-primary btn-xs icon-btn md-btn-flat"> <i class="ion ion-md-sync"></i> </button> </div> </h6> <div class="py-4 px-3"> <div style="height:162px;"> <canvas id="statistics-chart-6"></canvas> </div> </div> </div> <!-- / Type gadgets chart --> </div> <div class="col-md-6 col-lg-12 col-xl-6"> <!-- Comments --> <div class="card mb-4"> <h6 class="card-header">Comments</h6> <div class="card-body"> <div class="media pb-1 mb-3"> <img src="assets/img/avatars/9-small.png" class="d-block ui-w-40 rounded-circle" alt> <div class="media-body ml-3"> <a href="javascript:void(0)">Amanda Warner</a> <span class="text-muted">commented on</span> <a href="javascript:void(0)">Article Name</a> <p class="my-1">Cras sit amet nibh libero, in gravida nulla. Nulla vel metus scelerisque ante sollicitudin commodo.</p> <div class="clearfix"> <a href="javascript:void(0)" class="float-right text-lightest small"> <span class="ion ion-ios-thumbs-down"></span> </a> <a href="javascript:void(0)" class="float-right text-lightest small"> <span class="ion ion-ios-thumbs-up mr-2"></span> </a> <span class="float-left text-muted small">2 hours ago</span> </div> </div> </div> <div class="media pb-1 mb-3"> <img src="assets/img/avatars/8-small.png" class="d-block ui-w-40 rounded-circle" alt> <div class="media-body ml-3"> <a href="javascript:void(0)">Hallie Lewis</a> <span class="text-muted">commented on</span> <a href="javascript:void(0)">Article Name</a> <p class="my-1">Vivendum torquatos ut nec, sit audiam deterruisset ei, cu sed nibh autem scriptorem. Ea quo vidit deleniti constituto, ex qui malis mollis iudicabit, viris fabellas id has.</p> <div class="clearfix"> <a href="javascript:void(0)" class="float-right text-lightest small"> <span class="ion ion-ios-thumbs-down"></span> </a> <a href="javascript:void(0)" class="float-right text-lightest small"> <span class="ion ion-ios-thumbs-up mr-2"></span> </a> <span class="float-left text-muted small">2 hours ago</span> </div> </div> </div> <div class="media"> <img src="assets/img/avatars/7-small.png" class="d-block ui-w-40 rounded-circle" alt> <div class="media-body ml-3"> <a href="javascript:void(0)">Alice Hampton</a> <span class="text-muted">commented on</span> <a href="javascript:void(0)">Article Name</a> <p class="my-1">Eam facilis laboramus reprehendunt ei, ex esse fastidii per.</p> <div class="clearfix"> <a href="javascript:void(0)" class="float-right text-lightest small"> <span class="ion ion-ios-thumbs-down"></span> </a> <a href="javascript:void(0)" class="float-right text-lightest small"> <span class="ion ion-ios-thumbs-up mr-2"></span> </a> <span class="float-left text-muted small">2 hours ago</span> </div> </div> </div> </div> <a href="javascript:void(0)" class="card-footer d-block text-center text-body small font-weight-semibold">SHOW MORE</a> </div> <!-- / Comments --> </div> <div class="col-md-6 col-lg-12 col-xl-6"> <!-- Support tickets --> <div class="card mb-4"> <h6 class="card-header">Support tickets</h6> <div class="card-body"> <div class="pb-1 mb-3"> <div class="badge badge-outline-warning float-right">Feature</div> <a href="javascript:void(0)">Lorem ipsum dolor sit amet, vis erat denique in.</a> <span class="text-muted">#34563</span> <br> <small class="text-muted">Created by <a href="javascript:void(0)" class="text-body">Mike Greene</a> · 1 day ago</small> </div> <div class="pb-1 mb-3"> <div class="badge badge-outline-danger float-right">Bug</div> <a href="javascript:void(0)">Dicunt prodesset te vix.</a> <span class="text-muted">#34524</span> <br> <small class="text-muted">Created by <a href="javascript:void(0)" class="text-body">Leon Wilson</a> · 1 day ago</small> </div> <div class="pb-1 mb-3"> <div class="badge badge-outline-success float-right">Question</div> <a href="javascript:void(0)">Sit meis deleniti eu, pri vidit meliore docendi ut?</a> <span class="text-muted">#34563</span> <br> <small class="text-muted">Created by <a href="javascript:void(0)" class="text-body">Allie Rodriguez</a> · 1 day ago</small> </div> <div class="pb-1 mb-3"> <div class="badge badge-outline-secondary float-right">Enhancement</div> <a href="javascript:void(0)">Eu tantas offendit mnesarchum sit, vide novum ad pri.</a> <span class="text-muted">#34563</span> <br> <small class="text-muted">Created by <a href="javascript:void(0)" class="text-body"> Kenneth Frazier</a> · 1 day ago</small> </div> <div> <div class="badge badge-outline-danger float-right">Bug</div> <a href="javascript:void(0)">Dicunt prodesset te vix.</a> <span class="text-muted">#34524</span> <br> <small class="text-muted">Created by <a href="javascript:void(0)" class="text-body">Leon Wilson</a> · 1 day ago</small> </div> </div> <a href="javascript:void(0)" class="card-footer d-block text-center text-body small font-weight-semibold">SHOW MORE</a> </div> <!-- / Support tickets --> </div> </div> </div> <!-- / Content --> <!-- Layout footer --> <nav class="layout-footer footer bg-footer-theme"> <div class="container-fluid d-flex flex-wrap justify-content-between text-center container-p-x pb-3"> <div class="pt-3"> <span class="footer-text font-weight-bolder">Appwork</span> © </div> <div> <a href="javascript:void(0)" class="footer-link pt-3">About Us</a> <a href="javascript:void(0)" class="footer-link pt-3 ml-4">Help</a> <a href="javascript:void(0)" class="footer-link pt-3 ml-4">Contact</a> <a href="javascript:void(0)" class="footer-link pt-3 ml-4">Terms & Conditions</a> </div> </div> </nav> <!-- / Layout footer --> </div> <!-- Layout content --> </div> <!-- / Layout container --> </div> <!-- Overlay --> <div class="layout-overlay layout-sidenav-toggle"></div> </div> <!-- / Layout wrapper --> <!-- Core scripts --> <script src="assets/vendor/libs/popper/popper.js"></script> <script src="assets/vendor/js/bootstrap.js"></script> <script src="assets/vendor/js/sidenav.js"></script> <!-- Libs --> <script src="assets/vendor/libs/perfect-scrollbar/perfect-scrollbar.js"></script> <script src="assets/vendor/libs/chartjs/chartjs.js"></script> <!-- Demo --> <script src="assets/js/demo.js"></script> <script src="assets/js/dashboards_dashboard-1.js"></script> </body> </html>
(4)配置application.properties
#mysql spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/security?useUnicode=true&characterEncoding=utf-8&useSSL=true spring.datasource.username=root spring.datasource.password=123456 #mybatis整合 #该配置项就是指将带有下划线的表字段映射为驼峰格式的实体类属性。 mybatis.configuration.map-underscore-to-camel-case=true #该配置项就是指mapper文件位置,可以和DAO建立映射,否则出现not found异常 mybatis.mapper-locations=classpath:mapper/*.xml
(5)整合mybatis逆向工程生成代码,因为在pom.xml中已经加入mabatis的生成插件(必须添加版本号,否则异常),并指定了配置文件
generatorConfig.xml。
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <plugin> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-maven-plugin</artifactId> <version>1.4.0</version> <configuration> <configurationFile>src/main/resources/generatorConfig.xml</configurationFile> <overwrite>true</overwrite> <verbose>true</verbose> </configuration> </plugin> </plugins> </build>
在resources下直接创建文件
generatorConfig.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"> <generatorConfiguration> <!-- 数据库驱动:换成你本地的驱动包位置--> <classPathEntry location="D:\MavenRepository\mysql\mysql-connector-java\5.1.49\mysql-connector-java-5.1.49.jar"/> <context id="DB2Tables" targetRuntime="MyBatis3"> <commentGenerator> <property name="suppressDate" value="true"/> <!-- 是否去除自动生成的注释 true:是 : false:否 --> <property name="suppressAllComments" value="true"/> </commentGenerator> <!--数据库链接URL,用户名、密码 --> <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/security?characterEncoding=utf8" userId="root" password="123456"> </jdbcConnection> <javaTypeResolver> <property name="forceBigDecimals" value="false"/> </javaTypeResolver> <!-- 生成模型的包名和位置--> <javaModelGenerator targetPackage="cn.gwj.security.entity" targetProject="src/main/java"> <property name="enableSubPackages" value="true"/> <property name="trimStrings" value="true"/> </javaModelGenerator> <!-- 生成映射文件的包名和位置--> <sqlMapGenerator targetPackage="resources.mapper" targetProject="src/main"> <property name="enableSubPackages" value="true"/> </sqlMapGenerator> <!-- 生成DAO的包名和位置--> <javaClientGenerator type="XMLMAPPER" targetPackage="cn.gwj.security.dao" targetProject="src/main/java"> <property name="enableSubPackages" value="true"/> </javaClientGenerator> <!-- 要生成的表 tableName是数据库中的表名或视图名 domainObjectName是实体类名--> <table tableName="sys_user" domainObjectName="SysUser" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table> <table tableName="sys_role" domainObjectName="SysRole" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table> <table tableName="sys_user_role" domainObjectName="SysUserRole" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table> </context> </generatorConfiguration>
利用Maven的plugin直接双击generate生成代码:
可以生成entity、dao、mapper:
entity:生成实体的时候个别文件要重命名一下,因为生成的并不见得都符合规范
package cn.gwj.security.entity; import java.io.Serializable; public class SysUser implements Serializable { //实现序列号接口,保证对象序列化和反序列化的唯一性 static final long serialVersionUID = 1L; private Integer id; private String name; private String password; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name == null ? null : name.trim(); } public String getPassword() { return password; } public void setPassword(String password) { this.password = password == null ? null : password.trim(); } }
package cn.gwj.security.entity; import java.io.Serializable; public class SysRole implements Serializable { //实现序列号接口,保证对象序列化和反序列化的唯一性 static final long serialVersionUID = 1L; private Integer id; private String name; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name == null ? null : name.trim(); } }
package cn.gwj.security.entity; import java.io.Serializable; public class SysUserRole implements Serializable { //实现序列号接口,保证对象序列化和反序列化的唯一性 static final long serialVersionUID = 1L; private Integer userId; private Integer roleId; public Integer getUserId() { return userId; } public void setUserId(Integer userId) { this.userId = userId; } public Integer getRoleId() { return roleId; } public void setRoleId(Integer roleId) { this.roleId = roleId; } }
dao:
package cn.gwj.security.dao; import cn.gwj.security.entity.SysUser; public interface SysUserMapper { int deleteByPrimaryKey(Integer id); int insert(SysUser record); int insertSelective(SysUser record); SysUser selectByPrimaryKey(Integer id); SysUser selectByName(String name); int updateByPrimaryKeySelective(SysUser record); int updateByPrimaryKey(SysUser record); }
package cn.gwj.security.dao; import cn.gwj.security.entity.SysRole; public interface SysRoleMapper { int deleteByPrimaryKey(Integer id); int insert(SysRole record); int insertSelective(SysRole record); SysRole selectByPrimaryKey(Integer id); int updateByPrimaryKeySelective(SysRole record); int updateByPrimaryKey(SysRole record); }
package cn.gwj.security.dao; import cn.gwj.security.entity.SysUserRole; import java.util.List; public interface SysUserRoleMapper { int deleteByPrimaryKey(SysUserRole key); int insert(SysUserRole record); int insertSelective(SysUserRole record); List<SysUserRole> getListByuserId(Integer userId); }
SysUserMapper.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="cn.gwj.security.dao.SysUserMapper"> <resultMap id="BaseResultMap" type="cn.gwj.security.entity.SysUser"> <id column="id" jdbcType="INTEGER" property="id" /> <result column="name" jdbcType="VARCHAR" property="name" /> <result column="password" jdbcType="VARCHAR" property="password" /> </resultMap> <sql id="Base_Column_List"> id, name, password </sql> <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap"> select <include refid="Base_Column_List" /> from sys_user where id = #{id,jdbcType=INTEGER} </select> <select id="selectByName" parameterType="java.lang.String" resultMap="BaseResultMap"> select <include refid="Base_Column_List" /> from sys_user where name = #{name,jdbcType=VARCHAR} </select> <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer"> delete from sys_user where id = #{id,jdbcType=INTEGER} </delete> <insert id="insert" parameterType="cn.gwj.security.entity.SysUser"> insert into sys_user (id, name, password ) values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, #{password,jdbcType=VARCHAR} ) </insert> <insert id="insertSelective" parameterType="cn.gwj.security.entity.SysUser"> insert into sys_user <trim prefix="(" suffix=")" suffixOverrides=","> <if test="id != null"> id, </if> <if test="name != null"> name, </if> <if test="password != null"> password, </if> </trim> <trim prefix="values (" suffix=")" suffixOverrides=","> <if test="id != null"> #{id,jdbcType=INTEGER}, </if> <if test="name != null"> #{name,jdbcType=VARCHAR}, </if> <if test="password != null"> #{password,jdbcType=VARCHAR}, </if> </trim> </insert> <update id="updateByPrimaryKeySelective" parameterType="cn.gwj.security.entity.SysUser"> update sys_user <set> <if test="name != null"> name = #{name,jdbcType=VARCHAR}, </if> <if test="password != null"> password = #{password,jdbcType=VARCHAR}, </if> </set> where id = #{id,jdbcType=INTEGER} </update> <update id="updateByPrimaryKey" parameterType="cn.gwj.security.entity.SysUser"> update sys_user set name = #{name,jdbcType=VARCHAR}, password = #{password,jdbcType=VARCHAR} where id = #{id,jdbcType=INTEGER} </update> </mapper>
SysRoleMapper.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="cn.gwj.security.dao.SysRoleMapper"> <resultMap id="BaseResultMap" type="cn.gwj.security.entity.SysRole"> <id column="id" jdbcType="INTEGER" property="id" /> <result column="name" jdbcType="VARCHAR" property="name" /> </resultMap> <sql id="Base_Column_List"> id, name </sql> <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap"> select <include refid="Base_Column_List" /> from sys_role where id = #{id,jdbcType=INTEGER} </select> <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer"> delete from sys_role where id = #{id,jdbcType=INTEGER} </delete> <insert id="insert" parameterType="cn.gwj.security.entity.SysRole"> insert into sys_role (id, name) values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}) </insert> <insert id="insertSelective" parameterType="cn.gwj.security.entity.SysRole"> insert into sys_role <trim prefix="(" suffix=")" suffixOverrides=","> <if test="id != null"> id, </if> <if test="name != null"> name, </if> </trim> <trim prefix="values (" suffix=")" suffixOverrides=","> <if test="id != null"> #{id,jdbcType=INTEGER}, </if> <if test="name != null"> #{name,jdbcType=VARCHAR}, </if> </trim> </insert> <update id="updateByPrimaryKeySelective" parameterType="cn.gwj.security.entity.SysRole"> update sys_role <set> <if test="name != null"> name = #{name,jdbcType=VARCHAR}, </if> </set> where id = #{id,jdbcType=INTEGER} </update> <update id="updateByPrimaryKey" parameterType="cn.gwj.security.entity.SysRole"> update sys_role set name = #{name,jdbcType=VARCHAR} where id = #{id,jdbcType=INTEGER} </update> </mapper>
SysUserRoleMapper.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="cn.gwj.security.dao.SysUserRoleMapper"> <resultMap id="BaseResultMap" type="cn.gwj.security.entity.SysUserRole"> <id column="user_id" jdbcType="INTEGER" property="userId" /> <id column="role_id" jdbcType="INTEGER" property="roleId" /> </resultMap> <select id="getListByuserId" resultType="cn.gwj.security.entity.SysUserRole"> select user_id,role_id from sys_user_role where user_id=#{user_id} </select> <delete id="deleteByPrimaryKey" parameterType="cn.gwj.security.entity.SysUserRole"> delete from sys_user_role where user_id = #{userId,jdbcType=INTEGER} and role_id = #{roleId,jdbcType=INTEGER} </delete> <insert id="insert" parameterType="cn.gwj.security.entity.SysUserRole"> insert into sys_user_role (user_id, role_id) values (#{userId,jdbcType=INTEGER}, #{roleId,jdbcType=INTEGER}) </insert> <insert id="insertSelective" parameterType="cn.gwj.security.entity.SysUserRole"> insert into sys_user_role <trim prefix="(" suffix=")" suffixOverrides=","> <if test="userId != null"> user_id, </if> <if test="roleId != null"> role_id, </if> </trim> <trim prefix="values (" suffix=")" suffixOverrides=","> <if test="userId != null"> #{userId,jdbcType=INTEGER}, </if> <if test="roleId != null"> #{roleId,jdbcType=INTEGER}, </if> </trim> </insert> </mapper>
service:
package cn.gwj.security.service; import cn.gwj.security.dao.SysUserMapper; import cn.gwj.security.entity.SysUser; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class SysUserService { @Autowired private SysUserMapper userMapper; public SysUser selectById(Integer id) { return userMapper.selectByPrimaryKey(id); } public SysUser selectByName(String name) { return userMapper.selectByName(name); } }
package cn.gwj.security.service; import cn.gwj.security.dao.SysRoleMapper; import cn.gwj.security.entity.SysRole; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class SysRoleService { @Autowired private SysRoleMapper roleMapper; public SysRole selectById(Integer id){ return roleMapper.selectByPrimaryKey(id); } }
package cn.gwj.security.service; import cn.gwj.security.dao.SysUserRoleMapper; import cn.gwj.security.entity.SysUserRole; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @Service public class SysUserRoleService { @Autowired private SysUserRoleMapper userRoleMapper; public List<SysUserRole> listByUserId(Integer userId) { return userRoleMapper.getListByuserId(userId); } }
(6)配置spring security
自定义类CustomUserDetailsService实现UserDetailsService接口,并重写loadUserByUsername方法,组装数据并返回org.springframework.security.core.userdetails.User对象:
package cn.gwj.security.config; import cn.gwj.security.entity.SysRole; import cn.gwj.security.entity.SysUser; import cn.gwj.security.entity.SysUserRole; import cn.gwj.security.service.SysRoleService; import cn.gwj.security.service.SysUserRoleService; import cn.gwj.security.service.SysUserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.Collection; import java.util.List; @Service//只要加上注解,就会加入到spring容器替换掉spring security的默认userDetailsservicepublic class CustomUserDetailsService implements UserDetailsService { @Autowired private SysUserService userService; @Autowired private SysRoleService roleService; @Autowired private SysUserRoleService userRoleService; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { Collection<GrantedAuthority> authorities = new ArrayList<>(); // 从数据库中取出用户信息 SysUser user = userService.selectByName(username); // 判断用户是否存在 if(user == null) { throw new UsernameNotFoundException("用户名不存在"); } // 添加权限 List<SysUserRole> userRoles = userRoleService.listByUserId(user.getId()); for (SysUserRole userRole : userRoles) { SysRole role = roleService.selectById(userRole.getRoleId()); authorities.add(new SimpleGrantedAuthority(role.getName())); } // 返回UserDetails实现类 return new User(user.getName(), user.getPassword(), authorities); } }
创建类WebSecurityConfig继承自WebSecurityConfigurerAdapter,重写方法:
package cn.gwj.security.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true)//开启基于方法的安全认证机制,也就是说在web层的controller启用注解机制的安全确认 public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private CustomUserDetailsService userDetailsService; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService) .passwordEncoder(new BCryptPasswordEncoder());//密码加密 } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() // 如果有允许匿名的url,填在下面 // .antMatchers().permitAll() .anyRequest().authenticated() .and() // 设置登陆页 .formLogin().loginPage("/login") // 设置登陆成功页 .defaultSuccessUrl("/").permitAll() // 自定义登陆用户名和密码参数,默认为username和password // .usernameParameter("username") // .passwordParameter("password") .and() .logout().permitAll(); // 关闭CSRF跨域 http.csrf().disable(); } @Override public void configure(WebSecurity web) throws Exception { // 设置拦截忽略文件夹,可以对静态资源放行,AppWorkv1.4.0的资源都放在static下assets文件夹下了 web.ignoring().antMatchers("/assets/**", "/js/**"); } }
(7)预览
鉴于博客园只能上不大于10m文件,涉及资源分卷压缩。
https://files.cnblogs.com/files/gwjtssy/html-demo.part3.rar
https://files.cnblogs.com/files/gwjtssy/html-demo.part2.rar
https://files.cnblogs.com/files/gwjtssy/html-demo.part1.rar