博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【原】无脑操作:IDEA + maven + Shiro + SpringBoot + JPA + Thymeleaf实现基础授权权限
阅读量:6945 次
发布时间:2019-06-27

本文共 23386 字,大约阅读时间需要 77 分钟。

上一篇《》介绍了实现Shiro的基础认证。本篇谈谈实现Shiro的基础授权。

需求:

① 某系统有公共模块、领导模块、管理员模块三个业务模块,均需要登录系统后才可以访问。

② admin、leader、employee三个人职位分别是管理员、领导、员工,均可登录系统。

③ 不同职位的人登录系统后,能看到的功能模块不同。管理员可以访问全部三个模块。领导可以访问除去管理员模块外的两个模块。员工只能访问公共模块。

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------

分析:

典型的运用授权权限的需求,继续考虑使用Shiro。

问题1、认证和授权怎么理解呢?

答:一点粗浅理解,比如通过了美国的签证能进入美国了,这就是获得了认证。

但是进入美国了,也只能去有授权的地方玩玩,五角大楼能进么?没有授权是不给进的。

所以,授权是在认证获得后进一步的安全管理。

问题2、需求在描述什么场景?

答:需求中包含了基于角色的权限访问控制RBAC(Role-Based Access Control)的设计思路。

简单来说,单个人对某某资源可操作。

进一步考虑,如果是多个人对某某资源可操作呢?需要重复的这样设置么?运用归纳思想,把这样的多个人归为一类,形成了角色的概念。即这一角色的多个人对某某资源可操作。

RBAC认为权限授权实际上是Who、What、How的问题。在RBAC模型中,who、what、how构成了访问权限三元组,也就是“Who对What(Which)进行How的操作”。

问题3、针对本需求的RBAC设计是怎么样的?

答:简化设计为:用户和角色为多对一关系、角色和资源为多对多关系

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 0、数据库建表init.sql

1 -- 初始化 2 DROP TABLE sys_user; 3 DROP TABLE sys_role; 4 DROP TABLE sys_resource; 5 DROP TABLE sys_role_resource; 6  7 -- 用户信息表 8 CREATE TABLE sys_user 9 (10     userid INT AUTO_INCREMENT PRIMARY KEY COMMENT '用户编号',11     username VARCHAR(10) NOT NULL COMMENT '用户名称',12     `password` VARCHAR(10) NOT NULL COMMENT '用户密码',13     roleid INT NOT NULL COMMENT '角色编号'14 );15 16 INSERT INTO sys_user VALUES(NULL, 'admin', '123', 1), (NULL, 'leader', '456', 2), (NULL, 'employee', '789', 3);17 18 SELECT * FROM sys_user;19 20 -- 角色信息表21 CREATE TABLE sys_role22 (23     roleid INT AUTO_INCREMENT PRIMARY KEY COMMENT '角色编号',24     rolename VARCHAR(10) NOT NULL COMMENT '角色名称'25 );26 27 INSERT INTO sys_role VALUES(NULL, '管理员'), (NULL, '领导'), (NULL, '员工');28 29 SELECT * FROM sys_role;30 31 -- 资源信息表32 CREATE TABLE sys_resource33 (34     resourceid INT AUTO_INCREMENT PRIMARY KEY COMMENT '资源编号',35     resourcename VARCHAR(10) NOT NULL COMMENT '资源名称',36     resourceurl VARCHAR(50) NOT NULL COMMENT '资源URL'37 );38 39 INSERT INTO sys_resource VALUES40 (NULL, '公共模块', 'publicModule'),41 (NULL, '领导模块', 'leaderModule'),42 (NULL, '管理员模块', 'adminModule');43 44 SELECT * FROM sys_resource;45 46 -- 角色资源关联表47 CREATE TABLE sys_role_resource48 (49     id INT AUTO_INCREMENT PRIMARY KEY COMMENT '关联编号',50     roleid INT NOT NULL COMMENT '角色编号',51     resourceid INT NOT NULL COMMENT '资源编号'52 );53 54 INSERT INTO sys_role_resource VALUES55 (NULL, 1, 1), (NULL, 1, 2), (NULL, 1, 3),56 (NULL, 2, 1), (NULL, 2, 2),57 (NULL, 3, 1);58 59 SELECT * FROM sys_role_resource;60 61 -- 获取用户能访问的资源URL62 SELECT u.userid, rs.resourceurl63 FROM sys_role_resource AS rr64 INNER JOIN sys_resource AS rs ON rr.resourceid = rs.resourceid65 INNER JOIN sys_role AS r ON rr.roleid = r.roleid66 INNER JOIN sys_user AS u ON u.roleid = r.roleid67 WHERE u.userid = 1;

 

1、编写项目对象模型文件pom.xml

1 
2
5
4.0.0
6 7
cn.temptation
8
studyShiro
9
1.0-SNAPSHOT
10 11
12
org.springframework.boot
13
spring-boot-starter-parent
14
2.0.4.RELEASE
15
16 17
18
19
20
org.springframework.boot
21
spring-boot-starter-web
22
23
24
25
org.springframework.boot
26
spring-boot-starter-thymeleaf
27
28
29
30
org.springframework.boot
31
spring-boot-starter-data-jpa
32
33
34
35
org.mariadb.jdbc
36
mariadb-java-client
37
2.2.5
38
39
40
41
org.apache.shiro
42
shiro-spring
43
1.4.0
44
45
46
47
com.github.theborakompanioni
48
thymeleaf-extras-shiro
49
2.0.0
50
51
52
53
org.springframework.boot
54
spring-boot-devtools
55
true
56
57
58

 

2、编写项目配置文件application.properties

1 # 数据库访问配置 2 # 对应MariaDB驱动 3 spring.datasource.driverClassName=org.mariadb.jdbc.Driver 4  5 # 数据源配置 6 spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test 7 spring.datasource.username=root 8 spring.datasource.password=sa 9 10 # 配置Springboot默认支持的Hikari数据库连接池11 spring.datasource.type=com.zaxxer.hikari.HikariDataSource12 spring.datasource.hikari.minimum-idle=513 spring.datasource.hikari.maximum-pool-size=1514 spring.datasource.hikari.auto-commit=true15 spring.datasource.hikari.idle-timeout=3000016 spring.datasource.hikari.pool-name=DatebookHikariCP17 spring.datasource.hikari.max-lifetime=180000018 spring.datasource.hikari.connection-timeout=3000019 spring.datasource.hikari.connection-test-query=SELECT 120 21 # Spring Data JPA配置22 spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect23 spring.jpa.properties.hibernate.hbm2ddl.auto=update24 spring.jpa.show-sql=true25 spring.jpa.properties.hibernate.format_sql=true26 27 # 格式化输出的json字符串28 spring.jackson.serialization.indent_output=true29 30 # 设置控制台彩色打印31 spring.output.ansi.enabled=ALWAYS

 

3、编写项目启动类Application.java

1 package cn.temptation; 2  3 import org.springframework.boot.SpringApplication; 4 import org.springframework.boot.autoconfigure.SpringBootApplication; 5  6 @SpringBootApplication 7 public class Application { 8     public static void main(String[] args) { 9         // SpringBoot项目启动10         SpringApplication.run(Application.class, args);11     }12 }

 

4、编写全局异常处理类GlobalExceptionHandler.java

1 package cn.temptation.util; 2  3 import org.springframework.web.bind.annotation.ControllerAdvice; 4 import org.springframework.web.bind.annotation.ExceptionHandler; 5  6 /** 7  * 全局异常处理类 8  */ 9 @ControllerAdvice10 public class GlobalExceptionHandler {11     @ExceptionHandler(value = Exception.class)12     public String errorHandler(Exception exception) {13         return "redirect:/error/500";14     }15 }

 

5、编写错误页配置类ErrorPageConfig.java 和 错误页控制器ErrorController.java

错误页配置类ErrorPageConfig.java

1 package cn.temptation.util; 2  3 import org.springframework.boot.web.server.ErrorPage; 4 import org.springframework.boot.web.server.ErrorPageRegistrar; 5 import org.springframework.boot.web.server.ErrorPageRegistry; 6 import org.springframework.http.HttpStatus; 7 import org.springframework.stereotype.Component; 8  9 /**10  * 错误页配置类11  */12 @Component13 public class ErrorPageConfig implements ErrorPageRegistrar {14     @Override15     public void registerErrorPages(ErrorPageRegistry errorPageRegistry) {16         // 错误类型为401(无访问权限),显示401.html页面17         ErrorPage errorPage401 = new ErrorPage(HttpStatus.UNAUTHORIZED, "/error/401");18 19         // 错误类型为404(找不到资源),显示404.html页面20         ErrorPage errorPage404 = new ErrorPage(HttpStatus.NOT_FOUND, "/error/404");21 22         // 错误类型为500(服务器内部错误),显示500.html页面23         ErrorPage errorPage500 = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/500");24 25         errorPageRegistry.addErrorPages(errorPage401, errorPage404, errorPage500);26     }27 }

 

错误页控制器ErrorController.java

1 package cn.temptation.util; 2  3 import org.springframework.stereotype.Controller; 4 import org.springframework.web.bind.annotation.GetMapping; 5 import org.springframework.web.bind.annotation.RequestMapping; 6  7 /** 8  * 错误页控制器 9  */10 @Controller11 @RequestMapping("/error")12 public class ErrorController {13     // 401页面14     @GetMapping(value = "/401")15     public String error_401() {16         return "error/error_401";17     }18 19     // 404页面20     @GetMapping(value = "/404")21     public String error_404() {22         return "error/error_404";23     }24 25     // 500页面26     @GetMapping(value = "/500")27     public String error_500() {28         return "error/error_500";29     }30 }

 

6、编写错误页error_401.html、error_404.html 和 error_500.html

1  2  3  4     
5
6 401 7 69 70 71
72

没有授权

73

抱歉,您没有授权访问该页面

74
75 76
error_401
1  2  3  4     
5
6 404 7 69 70 71
72

没有找到:(

73

抱歉,您试图访问的页面不存在

74

可能是如下原因:

75
    76
  • 一个错误的地址
  • 77
  • 一个过时的链接
  • 78
79
80 81
error_404
1  2  3  4     
5
6 500 7 69 70 71
72

内部错误

73

抱歉,服务器上出现了错误......

74
75 76
error_500

 

6、编写登录页面login.html、首页页面index.html、公共模块页page_public.html、领导模块页page_leader.html 和 管理员模块页page_admin.html

1  2  3  4     
5 系统登录 6 7 8
9
10 帐号:
11 密码:
12
 
13
14 15
登录页
1  2  3  4     
5 系统首页 6 7 8
9
10
14
15
16
17
公共模块:
公共模块
18
领导模块:
领导模块
19
管理员模块:
管理员模块
20 21
首页
1  2  3  4     
5 公共模块 6 7 8 公共模块(管理员、领导、员工均可访问) 9 10
公共模块页
1  2  3  4     
5 领导模块 6 7 8 领导模块(管理员、领导均可访问) 9 10
领导模块页
1  2  3  4     
5 管理员模块 6 7 8 管理员模块(管理员可访问) 9 10
管理员模块页

 

7、编写Shiro框架用配置类ShiroConfig.java 和 自定义Realm类MyRealm.java

配置类ShiroConfig.java

1 package cn.temptation.shiro;  2   3 import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;  4 import cn.temptation.dao.ResourceDao;  5 import cn.temptation.domain.Resource;  6 import org.apache.shiro.spring.web.ShiroFilterFactoryBean;  7 import org.apache.shiro.web.mgt.DefaultWebSecurityManager;  8 import org.springframework.beans.factory.annotation.Autowired;  9 import org.springframework.beans.factory.annotation.Qualifier; 10 import org.springframework.context.annotation.Bean; 11 import org.springframework.context.annotation.Configuration; 12  13 import java.util.LinkedHashMap; 14 import java.util.List; 15 import java.util.Map; 16  17 /** 18  * Shiro配置类 19  */ 20 @Configuration 21 public class ShiroConfig { 22     @Autowired 23     private ResourceDao resourceDao; 24  25     // 1、创建ShiroFilterFactoryBean 26     @Bean 27     public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager) { 28         ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); 29         // 设置安全管理器 30         shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager); 31  32         // 设置登录跳转页面 33         shiroFilterFactoryBean.setLoginUrl("/login"); 34  35         /** 36          * Shiro内置过滤器:实现权限相关的拦截 37          *      常用过滤器: 38          *          anon(认证用):无需认证(登录)即可访问 39          *          authc(认证用):必须认证才可访问 40          *          user(少用):使用rememberMe功能可以访问 41          *          perms(授权用):必须得到资源权限才可访问 42          *          role(授权用):必须得到角色权限才可访问 43          */ 44         Map
filterMap = new LinkedHashMap<>(); 45 46 // 放行登录请求 47 filterMap.put("/doLogin", "anon"); 48 49 // 配置退出过滤器,退出代码Shiro已经实现 50 filterMap.put("/logout", "logout"); 51 52 // 配置授权过滤器 53 54 // 先代码写死,测试下 55 // filterMap.put("/publicModule", "perms[user:publicModule]"); 56 // filterMap.put("/leaderModule", "perms[user:leaderModule]"); 57 // filterMap.put("/adminModule", "perms[user:adminModule]"); 58 59 // 获取所有资源,并配置需要进行授权过滤的资源 60 List
resources = resourceDao.findAll(); 61 resources.forEach(item -> { 62 if (!"".equals(item.getResourceurl())) { 63 filterMap.put("/" + item.getResourceurl(), "perms[user:" + item.getResourceurl() + "]"); 64 } 65 }); 66 67 // 过滤链定义,从上向下顺序执行,一般将/*放在最下边 68 filterMap.put("/*", "authc"); 69 70 // 设置未授权界面 71 shiroFilterFactoryBean.setUnauthorizedUrl("/error/401"); 72 73 shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap); 74 75 return shiroFilterFactoryBean; 76 } 77 78 // 2、创建DefaultWebSecurityManager 79 @Bean(name = "securityManager") 80 public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("myRealm") MyRealm myRealm) { 81 DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager(); 82 83 // 关联Realm 84 defaultWebSecurityManager.setRealm(myRealm); 85 86 return defaultWebSecurityManager; 87 } 88 89 // 3、创建Realm 90 @Bean(name = "myRealm") 91 public MyRealm getRealm() { 92 return new MyRealm(); 93 } 94 95 // 4、配置ShiroDialect后,可以在页面使用Shiro标签 96 @Bean 97 public ShiroDialect getShiroDialect() { 98 return new ShiroDialect(); 99 }100 }

 

自定义Realm类MyRealm.java

1 package cn.temptation.shiro; 2  3 import cn.temptation.dao.ResourceDao; 4 import cn.temptation.dao.UserDao; 5 import cn.temptation.domain.User; 6 import org.apache.shiro.authc.*; 7 import org.apache.shiro.authz.AuthorizationInfo; 8 import org.apache.shiro.authz.SimpleAuthorizationInfo; 9 import org.apache.shiro.realm.AuthorizingRealm;10 import org.apache.shiro.subject.PrincipalCollection;11 import org.springframework.beans.factory.annotation.Autowired;12 13 import java.util.List;14 15 /**16  * 自定义Realm17  */18 public class MyRealm extends AuthorizingRealm {19     @Autowired20     private UserDao userDao;21     @Autowired22     private ResourceDao resourceDao;23 24     // 授权处理25     @Override26     protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {27         // 获取当前登录获得认证的用户28         User user = (User) principalCollection.getPrimaryPrincipal();29         // 下句语句会抛出异常交由ErrorController类根据ErrorPageConfig类中注册的响应码和错误页面处理30 //        System.out.println(1 / 0);31 32         if (user != null) {33             // 给资源授权34             SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();35 36             // 先代码写死,测试下37 //            info.addStringPermission("user:publicModule");38 //            info.addStringPermission("user:leaderModule");39 //            info.addStringPermission("user:adminModule");40 41             // 根据获得认证的用户编号查询该用户具备的资源URL集合42             List
resourceurls = resourceDao.findByUserid(user.getUserid());43 44 // 遍历集合,组装成满足授权过滤器过滤格式,并添加到资源信息中45 resourceurls.forEach(item -> info.addStringPermission("user:" + item));46 47 return info;48 }49 50 return null;51 }52 53 // 认证处理54 @Override55 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {56 // 编写Shiro判断逻辑,判断账号和密码57 // 1、判断账号58 UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;59 60 User user = userDao.findByUsername(token.getUsername());61 if (user == null) {62 // 账号错误,Shiro底层会抛出UnknownAccountException异常63 return null;64 }65 66 // 2、判断密码67 // 只做认证,principal可以设置为空字符串68 // return new SimpleAuthenticationInfo("", user.getPassword(), "");69 // 认证后做授权处理,需要将获得认证的用户对象赋值给principal,授权处理时会用到70 return new SimpleAuthenticationInfo(user, user.getPassword(), "");71 }72 }

 

8、编写用户实体类User.java、角色实体类Role.java 和 资源实体类Resource.java

用户实体类User.java

1 package cn.temptation.domain; 2  3 import javax.persistence.*; 4  5 @Entity 6 @Table(name = "sys_user") 7 public class User { 8     @Id 9     @GeneratedValue(strategy = GenerationType.IDENTITY)10     @Column(name = "userid")11     private Integer userid;12 13     @Column(name = "username")14     private String username;15 16     @Column(name = "password")17     private String password;18 19     @ManyToOne20     @JoinColumn(name = "roleid", foreignKey = @ForeignKey(name = "none"))21     private Role role;22 23     public Integer getUserid() {24         return userid;25     }26 27     public void setUserid(Integer userid) {28         this.userid = userid;29     }30 31     public String getUsername() {32         return username;33     }34 35     public void setUsername(String username) {36         this.username = username;37     }38 39     public String getPassword() {40         return password;41     }42 43     public void setPassword(String password) {44         this.password = password;45     }46 47     public Role getRole() {48         return role;49     }50 51     public void setRole(Role role) {52         this.role = role;53     }54 }

 

角色实体类Role.java

1 package cn.temptation.domain; 2  3 import javax.persistence.*; 4 import java.util.Set; 5  6 @Entity 7 @Table(name = "sys_role") 8 public class Role { 9     @Id10     @GeneratedValue(strategy = GenerationType.IDENTITY)11     @Column(name = "roleid")12     private Integer roleid;13 14     @Column(name = "rolename")15     private String rolename;16 17     @ManyToMany18     @JoinTable(name = "sys_role_resource",19             joinColumns = {@JoinColumn(name = "roleid", referencedColumnName = "roleid", foreignKey = @ForeignKey(name = "none"))},20             inverseJoinColumns = {@JoinColumn(name = "resourceid", referencedColumnName = "resourceid", foreignKey = @ForeignKey(name = "none"))})21     private Set
resources;22 23 public Integer getRoleid() {24 return roleid;25 }26 27 public void setRoleid(Integer roleid) {28 this.roleid = roleid;29 }30 31 public String getRolename() {32 return rolename;33 }34 35 public void setRolename(String rolename) {36 this.rolename = rolename;37 }38 }

 

资源实体类Resource.java

1 package cn.temptation.domain; 2  3 import javax.persistence.*; 4  5 @Entity 6 @Table(name = "sys_resource") 7 public class Resource { 8     @Id 9     @GeneratedValue(strategy = GenerationType.IDENTITY)10     @Column(name = "resourceid")11     private Integer resourceid;12 13     @Column(name = "resourcename")14     private String resourcename;15 16     @Column(name = "resourceurl")17     private String resourceurl;18 19     public Integer getResourceid() {20         return resourceid;21     }22 23     public void setResourceid(Integer resourceid) {24         this.resourceid = resourceid;25     }26 27     public String getResourcename() {28         return resourcename;29     }30 31     public void setResourcename(String resourcename) {32         this.resourcename = resourcename;33     }34 35     public String getResourceurl() {36         return resourceurl;37     }38 39     public void setResourceurl(String resourceurl) {40         this.resourceurl = resourceurl;41     }42 }

 

9、编写用户控制器类UserController.java

1 package cn.temptation.web; 2  3 import org.apache.shiro.SecurityUtils; 4 import org.apache.shiro.authc.IncorrectCredentialsException; 5 import org.apache.shiro.authc.UnknownAccountException; 6 import org.apache.shiro.authc.UsernamePasswordToken; 7 import org.apache.shiro.subject.Subject; 8 import org.springframework.stereotype.Controller; 9 import org.springframework.ui.Model;10 import org.springframework.web.bind.annotation.RequestMapping;11 12 @Controller13 public class UserController {14     // 访问登录页15     @RequestMapping("/login")16     public String login() {17         // 下句语句会抛出异常交由GlobalExceptionHandler类的errorHandler方法处理18 //        System.out.println(1 / 0);19 20         return "login";21     }22 23     // 访问首页24     @RequestMapping("/index")25     public String index() {26         return "index";27     }28 29     // 访问公共模块30     @RequestMapping("/publicModule")31     public String publicModule() {32         return "page_public";33     }34 35     // 访问私密模块36     @RequestMapping("/privateModule")37     public String privateModule() {38         return "page_leader";39     }40 41     // 登录处理42     @RequestMapping("/doLogin")43     public String doLogin(String username, String password, Model model) {44         // 使用Shiro编写认证处理45         // 1、获取Subject46         Subject subject = SecurityUtils.getSubject();47 48         // 2、封装用户数据49         UsernamePasswordToken token = new UsernamePasswordToken(username, password);50 51         // 3、执行登录52         try {53             // 登录成功54             subject.login(token);55 56             // 返回当前用户的帐号57             model.addAttribute("currentuser", token.getUsername());58 59             return "index";60         } catch (UnknownAccountException exception) {61             // 返回错误信息62             model.addAttribute("msg", "账号错误!");63 64             return "login";65         } catch (IncorrectCredentialsException exception) {66             // 返回错误信息67             model.addAttribute("msg", "密码错误!");68 69             return "login";70         }71     }72 73     // 注销处理74     @RequestMapping("/doLogout")75     public String doLogout() {76         // 1、获取Subject77         Subject subject = SecurityUtils.getSubject();78 79         // 2、执行注销80         try {81             subject.logout();82         } catch (Exception ex) {83             ex.printStackTrace();84         } finally {85             return "login";86         }87     }88 }

 

10、编写用户数据访问接口UserDao.java、角色数据访问接口RoleDao.java 和 资源数据访问接口ResourceDao.java

用户数据访问接口UserDao.java

1 package cn.temptation.dao; 2  3 import cn.temptation.domain.User; 4 import org.springframework.data.jpa.repository.JpaRepository; 5 import org.springframework.data.jpa.repository.Query; 6 import org.springframework.data.repository.query.Param; 7  8 public interface UserDao extends JpaRepository
{ 9 // 根据账号查询用户10 @Query(value = "SELECT * FROM sys_user WHERE username=:username", nativeQuery = true)11 User findByUsername(@Param("username") String username);12 }

 

角色数据访问接口RoleDao.java

1 package cn.temptation.dao;2 3 import cn.temptation.domain.Role;4 import org.springframework.data.jpa.repository.JpaRepository;5 6 public interface RoleDao extends JpaRepository
{7 8 }

 

资源数据访问接口ResourceDao.java

1 package cn.temptation.dao; 2  3 import cn.temptation.domain.Resource; 4 import org.springframework.data.jpa.repository.JpaRepository; 5 import org.springframework.data.jpa.repository.Query; 6 import org.springframework.data.repository.query.Param; 7  8 import java.util.List; 9 10 public interface ResourceDao extends JpaRepository
{11 @Query(value = "SELECT rs.resourceurl FROM sys_role_resource AS rr " +12 "INNER JOIN sys_resource AS rs ON rr.resourceid = rs.resourceid " +13 "INNER JOIN sys_role AS r ON rr.roleid = r.roleid " +14 "INNER JOIN sys_user AS u ON u.roleid = r.roleid WHERE u.userid = :userid ", nativeQuery = true)15 List
findByUserid(@Param("userid") Integer userid);16 }

 

11、项目结构

 

 

12、运行效果

 

转载于:https://www.cnblogs.com/iflytek/p/9847809.html

你可能感兴趣的文章
JAVA IO之管道流总结大全(转)
查看>>
字符串转换为数值类型
查看>>
省流量攻略
查看>>
Redis基础知识 之——发布/订阅
查看>>
Netty《一》
查看>>
KVC and Scalar
查看>>
Java 容器源码分析之 ArrayList
查看>>
PHP经典乱码“口”字与解决办法
查看>>
万能的js复制按钮
查看>>
jquery中的trigger()和preventDefault()方法
查看>>
Atitit. 数据库-----catalog与schema的设计区别以及在实际中使用 获取数据库所有库表 java jdbc php c#.Net...
查看>>
UIView属性clipsTobounds的应用
查看>>
常用chrome插件&&常用FireFox插件
查看>>
ip push
查看>>
$().index() 两种用法
查看>>
2440开发板linux系统移植3G拨号上网收发短信(三)
查看>>
“跳一跳”小游戏这么火爆,它是如何做的设计和开发?
查看>>
微软收购开源数据库厂商Citus Data,云数据库服务能力再填新砝码
查看>>
【内购篇】5 分钟教你成为会赚钱的独立开发者
查看>>
我的if else代码纯净无暇,一个字也不能简化
查看>>