1. 程式人生 > >spring boot2.0+shiro+mybatis多資料來源+druid連線池專案整合

spring boot2.0+shiro+mybatis多資料來源+druid連線池專案整合

關於整合

   網上關於springboot2.0和shiro+myabtis整合的案例很少,大神的教程也是用jpa編寫,jpa很方便,但是還有很多人用mybatis,加之剛學習完mybatis多資料來源整合和druid連線池監控配置,所以算是階段性記錄。

專案目錄

POM檔案

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.example</groupId>
	<artifactId>mybatisdemo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>mybatisdemo</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.4.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>1.3.2</version>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<optional>true</optional>
		</dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>
		<dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        </dependency>
		<dependency>
			<groupId> org.springframework.boot </groupId>
			<artifactId> spring-boot-configuration-processor </artifactId>
			<optional> true </optional>
		</dependency>
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-spring</artifactId>
			<version>1.4.0</version>
		</dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>


</project>

application.yml檔案

server:
  port: 8080

spring:
  datasource:
    druid:
      test1:
        #配置監控統計攔截的filters,去掉後監控介面SQL無法進行統計,'wall'用於防火牆
        filters: stat,wall
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
        username: root
        password: root
        #初始化大小
        initial-size: 1
        #最小連線數
        min-idle: 1
        #最大連線數
        max-active: 20
        #獲取連線等待超時時間
        max-wait: 60000
        #間隔多久才進行一次檢測,檢測需要關閉的空閒連線,單位毫秒
        time-between-eviction-runs-millis: 60000
        #一個連線在池中最小生存的時間,單位是毫秒
        min-evictable-idle-time-millis: 30000
        #測試語句是否執行正確
        validation-query: SELECT 'x'
        #指明連線是否被空閒連接回收器(如果有)進行檢驗.如果檢測失敗,則連線將被從池中去除.
        test-while-idle: true
        #借出連線時不要測試,否則很影響效能
        test-on-borrow: false
        test-on-return: false
        #開啟PSCache,並指定每個連線上PSCache的大小。oracle設為true,mysql設為false。分庫分表較多推薦設定為false
        pool-prepared-statements: false
        #與Oracle資料庫PSCache有關,再druid下可以設定的比較高
        max-pool-prepared-statement-per-connection-size: 20
      #資料來源2
      test2:
        filters: stat,wall
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:3306/mytest2?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
        username: root
        password: root
        initial-size: 1
        min-idle: 1
        max-active: 20
        max-wait: 60000
        time-between-eviction-runs-millis: 60000
        min-evictable-idle-time-millis: 30000
        validation-query: SELECT 'x'
        test-while-idle: true
        test-on-borrow: false
        test-on-return: false
        pool-prepared-statements: false
        max-pool-prepared-statement-per-connection-size: 20

  thymeleaf:
    cache: false
    mode: LEGACYHTML5

資料來源1配置

package com.example.mybatisdemo.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

@Configuration
@MapperScan(basePackages = "com.example.mybatisdemo.dao1",sqlSessionTemplateRef = "test1SqlSessionTemplate")
public class DataSource1Config {

    @Bean(name = "test1DataSource")
    @ConfigurationProperties(prefix = "spring.datasource.druid.test1")
    @Primary
    public DruidDataSource test1DataSource(){
        return DruidDataSourceBuilder.create().build();
    }

    @Bean(name = "test1SqlSessionFactory")
    @Primary
    public SqlSessionFactory test1sqlSessionFactory(@Qualifier("test1DataSource") DruidDataSource druidDataSource) throws Exception{
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(druidDataSource);
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));
        return bean.getObject();
    }

    @Bean(name = "test1TransactionManager")
    @Primary
    public DataSourceTransactionManager test1TransactionManager(@Qualifier("test1DataSource")DruidDataSource druidDataSource){
        return new DataSourceTransactionManager(druidDataSource);
    }

    @Bean(name = "test1SqlSessionTemplate")
    @Primary
    public SqlSessionTemplate test1SqlSessionTemplate(@Qualifier("test1SqlSessionFactory")SqlSessionFactory sqlSessionFactory){
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

資料來源2配置

package com.example.mybatisdemo.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

@Configuration
@MapperScan(basePackages = "com.example.mybatisdemo.dao2",sqlSessionTemplateRef = "test2SqlSessionTemplate")
public class DataSource2Config {

    @Bean(name = "test2DataSource")
    @ConfigurationProperties(prefix = "spring.datasource.druid.test2")
//    @Primary
    public DruidDataSource test2DataSource(){
        return DruidDataSourceBuilder.create().build();
    }

    @Bean(name = "test2SqlSessionFactory")
//    @Primary
    public SqlSessionFactory test2sqlSessionFactory(@Qualifier("test2DataSource") DruidDataSource druidDataSource) throws Exception{
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(druidDataSource);
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));
        return bean.getObject();
    }

    @Bean(name = "test2TransactionManager")
//    @Primary
    public DataSourceTransactionManager test2TransactionManager(@Qualifier("test2DataSource")DruidDataSource druidDataSource){
        return new DataSourceTransactionManager(druidDataSource);
    }

    @Bean(name = "test2SqlSessionTemplate")
//    @Primary
    public SqlSessionTemplate test2SqlSessionTemplate(@Qualifier("test2SqlSessionFactory")SqlSessionFactory sqlSessionFactory){
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

Druid連線池監控配置

package com.example.mybatisdemo.config;

import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class DruidConfig {

    /**
     * 註冊servlet資訊,配置監控圖
     *
     */

    @Bean
    @ConditionalOnMissingBean
    public ServletRegistrationBean druidServlet(){
        ServletRegistrationBean servletRegistrationBean =
            new ServletRegistrationBean(new StatViewServlet(),"/druid/*");
        //白名單
        servletRegistrationBean.addInitParameter("allow","192.168.6.195");
        //IP黑名單(存在共同時,deny優先於allow) : 如果滿足deny的話提示:Sorry, you are not permitted to view this page.
        servletRegistrationBean.addInitParameter("deny","192.168.6.73");
        //用於登陸的賬號密碼
        servletRegistrationBean.addInitParameter("loginUsername","admin");
        servletRegistrationBean.addInitParameter("loginPassword","admin");
        //是否能重置資料
        servletRegistrationBean.addInitParameter("resetEnable","true");
        return servletRegistrationBean;
    }
    /**
     *
     * 註冊filter資訊,用於攔截
     */

    @Bean
    @ConditionalOnMissingBean
    public FilterRegistrationBean filterRegistrationBean(){
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new WebStatFilter());
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
        return filterRegistrationBean;
    }
}

關於RABC角色訪問控制

RBAC 是基於角色的訪問控制(Role-Based Access Control )在 RBAC 中,許可權與角色相關聯,使用者通過成為適當角色的成員而得到這些角色的許可權。這就極大地簡化了許可權的管理。這樣管理都是層級相互依賴的,許可權賦予給角色,而把角色又賦予使用者,這樣的許可權設計很清楚,管理起來很方便。

建表過程

CREATE TABLE `sys_permission` (
  `id` int(11) NOT NULL,
  `available` bit(1) DEFAULT NULL,
  `name` varchar(255) DEFAULT NULL,
  `parent_id` bigint(20) DEFAULT NULL,
  `parent_ids` varchar(255) DEFAULT NULL,
  `permission` varchar(255) DEFAULT NULL,
  `resource_type` enum('menu','button') DEFAULT NULL,
  `url` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4
CREATE TABLE `sys_role` (
  `id` int(11) NOT NULL,
  `available` bit(1) DEFAULT NULL,
  `description` varchar(255) DEFAULT NULL,
  `role` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4
CREATE TABLE `user_info` (
  `uid` int(11) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  `salt` varchar(255) DEFAULT NULL,
  `state` tinyint(4) NOT NULL,
  `username` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`uid`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4
CREATE TABLE `sys_role_permission` (
  `permission_id` int(11) NOT NULL,
  `role_id` int(11) NOT NULL,
  KEY `FK9q28ewrhntqeipl1t04kh1be7` (`role_id`),
  KEY `FKomxrs8a388bknvhjokh440waq` (`permission_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4
CREATE TABLE `sys_user_role` (
  `role_id` int(11) NOT NULL,
  `uid` int(11) NOT NULL,
  KEY `FKgkmyslkrfeyn9ukmolvek8b8f` (`uid`),
  KEY `FKhh52n8vd4ny9ff4x9fb8v65qx` (`role_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4

插入測試資料 

INSERT INTO `user_info` (`uid`,`username`,`name`,`password`,`salt`,`state`) VALUES ('1', 'admin', '管理員', 'd3c59d25033dbf980d29554025c23a75', '8d78869f470951332959580424d4bf4f', 0);
INSERT INTO `sys_permission` (`id`,`available`,`name`,`parent_id`,`parent_ids`,`permission`,`resource_type`,`url`) VALUES (1,0,'使用者管理',0,'0/','userInfo:view','menu','userInfo/userList');
INSERT INTO `sys_permission` (`id`,`available`,`name`,`parent_id`,`parent_ids`,`permission`,`resource_type`,`url`) VALUES (2,0,'使用者新增',1,'0/1','userInfo:add','button','userInfo/userAdd');
INSERT INTO `sys_permission` (`id`,`available`,`name`,`parent_id`,`parent_ids`,`permission`,`resource_type`,`url`) VALUES (3,0,'使用者刪除',1,'0/1','userInfo:del','button','userInfo/userDel');
INSERT INTO `sys_role` (`id`,`available`,`description`,`role`) VALUES (1,0,'管理員','admin');
INSERT INTO `sys_role` (`id`,`available`,`description`,`role`) VALUES (2,0,'VIP會員','vip');
INSERT INTO `sys_role` (`id`,`available`,`description`,`role`) VALUES (3,1,'test','test');
INSERT INTO `sys_role_permission` VALUES ('1', '1');
INSERT INTO `sys_role_permission` (`permission_id`,`role_id`) VALUES (1,1);
INSERT INTO `sys_role_permission` (`permission_id`,`role_id`) VALUES (2,1);
INSERT INTO `sys_role_permission` (`permission_id`,`role_id`) VALUES (3,2);
INSERT INTO `sys_user_role` (`role_id`,`uid`) VALUES (1,1);

實體類(getter setter方法自行實現)

package com.example.mybatisdemo.domain;

public class Permission {

    private Integer id;
    private Boolean available;
    private String name;
    private Long parent_id;
    private String parent_ids;
    private String permission;
    private String resource_type;
    private String url;}
package com.example.mybatisdemo.domain;

public class Role {

    private Integer id;
    private Boolean available;
    private String description;
    private String role;
}
package com.example.mybatisdemo.domain;

public class UserInfo {

    private Integer uid;

    private String name;

    private String username;

    private String password;

    private String salt;

    private byte state;

    //密碼加鹽
    public String getCredentialsSalt(){
        return this.username+this.salt;
    }
}

鹽值由資料庫中的salt和賬號組合而成

DAO層

因為多資料來源配置,dao層有兩個並分開使用,可以一個設計資料一個設計使用者驗證,這裡只實現使用者驗證放dao1中

package com.example.mybatisdemo.dao1;

import com.example.mybatisdemo.domain.Permission;
import com.example.mybatisdemo.domain.Role;
import com.example.mybatisdemo.domain.UserInfo;

import java.util.List;

public interface UserInfoDao {

    UserInfo selectByUsername(String username);

    List<Integer> selectRoleidByUid(Integer uid);

    Role selectRoleById(Integer id);

    List<Integer> selectPermissionidByRoleid(Integer roleid);

    Permission selectPermissionById(Integer permissionid);
}

Mapper實現

<?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="com.example.mybatisdemo.dao1.UserInfoDao">

    <sql id="BASE_COLUMN">
        uid,name,password,salt,state,username
    </sql>
    <sql id="BASE_TABLE">
        user_info
    </sql>
    <sql id="USERNAME">
        username
    </sql>
    <sql id="ROLEID">
        role_id
    </sql>
    <sql id="USERROLE">
        sys_user_role
    </sql>
    <sql id="ROLE_COLUMN">
        id,available,description,role
    </sql>
    <sql id="ROLETABLE">
        sys_role
    </sql>
    <sql id="PERMISSIONID">
      permission_id
    </sql>
    <sql id="ROLEPERMISSION">
      sys_role_permission
    </sql>
    <sql id="PERMISSIONCOLUNMN">
        id,available,name,parent_id,parent_ids,permission,resource_type,url
    </sql>
    <sql id="PERMISSIONTABLE">
        sys_permission
    </sql>
    <select id="selectByUsername" resultType="com.example.mybatisdemo.domain.UserInfo" parameterType="java.lang.String">
        select
        <include refid="BASE_COLUMN"/>
        FROM
        <include refid="BASE_TABLE"/>
        WHERE
        <include refid="USERNAME"/>
        <trim prefix="=">
          #{username,jdbcType=VARCHAR}
        </trim>
    </select>
    <select id="selectRoleidByUid" resultType="java.lang.Integer" parameterType="java.lang.Integer">
        SELECT
        <include refid="ROLEID"/>
        FROM
        <include refid="USERROLE"/>
        WHERE uid
        <trim prefix="=">
            #{uid,jdbcType=INTEGER}
        </trim>
    </select>
    <select id="selectRoleById" resultType="com.example.mybatisdemo.domain.Role" >
        SELECT
        <include refid="ROLE_COLUMN"/>
        FROM
        <include refid="ROLETABLE"/>
        WHERE id
        <trim prefix="=">
            #{id, jdbcType=INTEGER}
        </trim>
    </select>
    <select id="selectPermissionidByRoleid" resultType="java.lang.Integer" parameterType="java.lang.Integer">
        SELECT
        <include refid="PERMISSIONID"/>
        FROM
        <include refid="ROLEPERMISSION"/>
        where
        <include refid="ROLEID"/>
        <trim prefix="=">
            #{roleid, jdbcType=INTEGER}
        </trim>
    </select>
    <select id="selectPermissionById" resultType="com.example.mybatisdemo.domain.Permission">
        SELECT 
        <include refid="PERMISSIONCOLUNMN"/>
        FROM
        <include refid="PERMISSIONTABLE"/>
        WHERE id
        <trim prefix="=">
          #{id, jdbcType=INTEGER}
        </trim>
    </select>
</mapper>

Service層

package com.example.mybatisdemo.service;

import com.example.mybatisdemo.domain.Permission;
import com.example.mybatisdemo.domain.Role;
import com.example.mybatisdemo.domain.UserInfo;

import java.util.List;

public interface UserInfoService {

    UserInfo findByUsername(String username);

    Role findRoleById(Integer id);

    List<Integer> findRoleidByUid(Integer uid);

    List<Integer> findPermissionidByRoleid(Integer roleid);

    Permission findPermissionById(Integer permissionid);
}

Service層實現

package com.example.mybatisdemo.service.impl;

import com.example.mybatisdemo.dao1.UserInfoDao;
import com.example.mybatisdemo.domain.Permission;
import com.example.mybatisdemo.domain.Role;
import com.example.mybatisdemo.domain.UserInfo;
import com.example.mybatisdemo.service.UserInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service(value = "userInfoService")
public class UserInfoServiceImpl implements UserInfoService {

    @Autowired
    private UserInfoDao userInfoDao;

    @Override
    public UserInfo findByUsername(String username) {
        return userInfoDao.selectByUsername(username);
    }

    @Override
    public Role findRoleById(Integer id) {
        return userInfoDao.selectRoleById(id);
    }

    @Override
    public List<Integer> findRoleidByUid(Integer uid) {
        return userInfoDao.selectRoleidByUid(uid);
    }

    @Override
    public List<Integer> findPermissionidByRoleid(Integer roleid) {
        return userInfoDao.selectPermissionidByRoleid(roleid);
    }

    @Override
    public Permission findPermissionById(Integer permissionid) {
        return userInfoDao.selectPermissionById(permissionid);
    }
}

Web層

package com.example.mybatisdemo.web;

import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

@Controller
public class HomeController {

    @RequestMapping({"/","/index"})
    public String index(){
        return "/index";
    }

    @RequestMapping("/login")
    public String login(HttpServletRequest request, Map<String,Object> map) throws Exception{
        System.out.println("登入頁面");
        // 登入失敗從request中獲取shiro處理的異常資訊。
        // shiroLoginFailure:就是shiro異常類的全類名.
        String exception = (String) request.getAttribute("shiroLoginFailure");
        System.out.println("exception="+exception);
        String msg = "";
        if (exception!=null){
            if (UnknownAccountException.class.getName().equals(exception)){
                System.out.println("賬號不存在");
                msg = "賬號不存在";
            } else if (IncorrectCredentialsException.class.getName().equals(exception)){
                System.out.println("密碼不正確");
            } else if ("kaptchaValidateFailed".equals(exception)){
                System.out.println("驗證碼不正確");
            } else {
                msg ="else  "+exception;
                System.out.println("else  "+exception);
            }
        }
        map.put("msg",msg);
        return "login";
    }

    @RequestMapping("/403")
    public String unauthorizaRole(){
        System.out.println("沒有許可權");
        return "/403";
    }

    @RequestMapping("/registered")
    public String registered(){
        return "/registered";
    }
}
package com.example.mybatisdemo.web;

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

@Controller
@RequestMapping("/nofilter")
public class NoFiltercController {

    @RequestMapping("/nofilter")
    public String nofilter(){
        return "static/nofilter";
    }
}

在/nofilter下的所有連結都可以匿名訪問

package com.example.mybatisdemo.web;

import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/userInfo")
public class UserInfoController {

    @RequestMapping("/userList")
    @RequiresPermissions("userInfo:view")
    public String userInfo(){
        return "userInfo";
    }

    @RequestMapping("/userAdd")
    @RequiresPermissions("userInfo:add")
    public String userInfoAdd(){
        return "userInfoAdd";
    }

    @RequestMapping("/userDel")
    @RequiresPermissions("UserInfo:del")
    public String userInfoDel(){
        return "userInfoDel";
    }
}

/userinfo下的所有連線都需要驗證登陸後實現

關於頁面

除了login.html之外都很簡單,貼出login.html和index.html,其他的網頁都可以仿照index.html實現

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Login</title>
</head>
<body>
錯誤資訊:<h4 th:text="${msg}"></h4>
<form action="" method="post">
    <p>賬號:<input type="text" name="username" value="admin"/></p>
    <p>密碼:<input type="text" name="password" value="123456"/></p>
    <p><input type="submit" value="登入"/>
        <button onclick="window.location.href='/registered'" type="button">註冊
        </button>
    </p>

</form>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index</title>
</head>
<body>
<h1>index</h1>
</body>
</html>

測試

3、修改admin不同的許可權進行測試

阿里雲druid真的很好用

至此專案結束,網上基本搜不到這些整合,我也是初學者 靠自己摸索出來的經驗,希望能幫助大家,做個參考,有些地方寫的很麻煩。註冊沒有寫完,加密可以用new Md5Hash("source","salt",2);來獲取,shiro沒有關於註冊的封裝,所以註冊須自己實現。