SpringBoot2.1.6 + Shiro1.4.1 + Thymeleaf + Jpa整合練習


  首先,添加maven依賴,完整的pom文件如下:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 4     <modelVersion>4.0.0</modelVersion>
 5     <parent>
 6         <groupId>org.springframework.boot</groupId>
 7         <artifactId>spring-boot-starter-parent</artifactId>
 8         <version>2.1.6.RELEASE</version>
 9         <relativePath/> <!-- lookup parent from repository -->
10     </parent>
11     <groupId>com.hui</groupId>
12     <artifactId>SpringBoot22</artifactId>
13     <version>0.0.1-SNAPSHOT</version>
14     <name>SpringBoot22</name>
15     <description>Demo project for Spring Boot</description>
16 
17     <properties>
18         <java.version>1.8</java.version>
19     </properties>
20 
21     <dependencies>
22         <dependency>
23             <groupId>org.springframework.boot</groupId>
24             <artifactId>spring-boot-starter-web</artifactId>
25         </dependency>
26 
27         <dependency>
28             <groupId>mysql</groupId>
29             <artifactId>mysql-connector-java</artifactId>
30             <scope>runtime</scope>
31         </dependency>
32         <dependency>
33             <groupId>org.springframework.boot</groupId>
34             <artifactId>spring-boot-starter-test</artifactId>
35             <scope>test</scope>
36         </dependency>
37         <dependency>
38             <groupId>org.apache.shiro</groupId>
39             <artifactId>shiro-spring</artifactId>
40             <version>1.4.1</version>
41         </dependency>
42         <dependency>
43             <groupId>org.springframework.boot</groupId>
44             <artifactId>spring-boot-starter-data-jpa</artifactId>
45             <version>RELEASE</version>
46         </dependency>
47         <dependency>
48             <groupId>org.springframework.boot</groupId>
49             <artifactId>spring-boot-starter-thymeleaf</artifactId>
50             <version>RELEASE</version>
51         </dependency>
52     </dependencies>
53 
54     <build>
55         <plugins>
56             <plugin>
57                 <groupId>org.springframework.boot</groupId>
58                 <artifactId>spring-boot-maven-plugin</artifactId>
59             </plugin>
60         </plugins>
61     </build>
62 
63 </project>

  接着,我們先編寫自定義的Realm類(MyJbdcRealm)

  1 package com.hui.SpringBoot22.realm;
  2 
  3 import org.apache.shiro.authc.*;
  4 import org.apache.shiro.authz.AuthorizationException;
  5 import org.apache.shiro.authz.AuthorizationInfo;
  6 import org.apache.shiro.authz.SimpleAuthorizationInfo;
  7 import org.apache.shiro.realm.AuthorizingRealm;
  8 import org.apache.shiro.subject.PrincipalCollection;
  9 import org.apache.shiro.util.ByteSource;
 10 import org.apache.shiro.util.JdbcUtils;
 11 
 12 import javax.sql.DataSource;
 13 import java.sql.Connection;
 14 import java.sql.PreparedStatement;
 15 import java.sql.ResultSet;
 16 import java.sql.SQLException;
 17 import java.util.Arrays;
 18 import java.util.Collection;
 19 import java.util.LinkedHashSet;
 20 import java.util.Set;
 21 
 22 public class MyJdbcRealm extends AuthorizingRealm {
 23 
 24     protected static final String DEFAULT_AUTHENTICATION_QUERY = "select password from users where username = ?";
 25     protected static final String DEFAULT_USER_ROLES_QUERY = "select role_name from user_roles where username = ?";
 26     protected static final String DEFAULT_PERMISSIONS_QUERY = "select permission from roles_permissions where role_name = ?";
 27     protected DataSource dataSource;
 28     protected String authenticationQuery = DEFAULT_AUTHENTICATION_QUERY;
 29     protected String userRolesQuery = DEFAULT_USER_ROLES_QUERY;
 30     protected String permissionsQuery = DEFAULT_PERMISSIONS_QUERY;
 31     protected boolean permissionsLookupEnabled = false;
 32 
 33     public void setDataSource(DataSource dataSource) {
 34         this.dataSource = dataSource;
 35     }
 36 
 37     public void setAuthenticationQuery(String authenticationQuery) {
 38         this.authenticationQuery = authenticationQuery;
 39     }
 40 
 41     public void setUserRolesQuery(String userRolesQuery) {
 42         this.userRolesQuery = userRolesQuery;
 43     }
 44 
 45     public void setPermissionsQuery(String permissionsQuery) {
 46         this.permissionsQuery = permissionsQuery;
 47     }
 48 
 49     public void setPermissionsLookupEnabled(boolean permissionsLookupEnabled) {
 50         this.permissionsLookupEnabled = permissionsLookupEnabled;
 51     }
 52 
 53     protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
 54         UsernamePasswordToken upToken = (UsernamePasswordToken) token;
 55         String username = upToken.getUsername();
 56         if (username == null) {
 57             throw new AccountException("Null usernames are not allowed by this realm.");
 58         }
 59         Connection conn = null;
 60         SimpleAuthenticationInfo info = null;
 61         try {
 62             conn = dataSource.getConnection();
 63             String password = null;
 64             password = getPasswordForUser(conn, username);
 65             if (password == null) {
 66                 throw new UnknownAccountException("No account found for user [" + username + "]");
 67             }
 68             info = new SimpleAuthenticationInfo(username, password.toCharArray(), getName());
 69         } catch (SQLException e) {
 70             final String message = "There was a SQL error while authenticating user [" + username + "]";
 71             throw new AuthenticationException(message, e);
 72         } finally {
 73             JdbcUtils.closeConnection(conn);
 74         }
 75         return info;
 76     }
 77 
 78     private String getPasswordForUser(Connection conn, String username) throws SQLException {
 79         String result = null;
 80         PreparedStatement ps = null;
 81         ResultSet rs = null;
 82         try {
 83             ps = conn.prepareStatement(authenticationQuery);
 84             ps.setString(1, username);
 85             rs = ps.executeQuery();
 86             boolean foundResult = false;
 87             while (rs.next()) {
 88                 if (foundResult) {
 89                     throw new AuthenticationException("More than one user row found for user [" + username + "]. Usernames must be unique.");
 90                 }
 91                 result = rs.getString(1);
 92                 foundResult = true;
 93             }
 94         } finally {
 95             JdbcUtils.closeResultSet(rs);
 96             JdbcUtils.closeStatement(ps);
 97         }
 98         return result;
 99     }
100 
101     @Override
102     protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
103         if (principals == null) {
104             throw new AuthorizationException("PrincipalCollection method argument cannot be null.");
105         }
106         String username = (String) getAvailablePrincipal(principals);
107         Connection conn = null;
108         Set<String> roleNames = null;
109         Set<String> permissions = null;
110         try {
111             conn = dataSource.getConnection();
112             roleNames = getRoleNamesForUser(conn, username);
113             if (permissionsLookupEnabled) {
114                 permissions = getPermissions(conn, username, roleNames);
115             }
116         } catch (SQLException e) {
117             final String message = "There was a SQL error while authorizing user [" + username + "]";
118             throw new AuthorizationException(message, e);
119         } finally {
120             JdbcUtils.closeConnection(conn);
121         }
122         SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roleNames);
123         info.setStringPermissions(permissions);
124         return info;
125     }
126 
127     protected Set<String> getRoleNamesForUser(Connection conn, String username) throws SQLException {
128         PreparedStatement ps = null;
129         ResultSet rs = null;
130         Set<String> roleNames = new LinkedHashSet<String>();
131         try {
132             ps = conn.prepareStatement(userRolesQuery);
133             ps.setString(1, username);
134             rs = ps.executeQuery();
135             while (rs.next()) {
136                 String roleName = rs.getString(1);
137                 if (roleName != null) {
138                     roleNames.add(roleName);
139                 }
140             }
141         } finally {
142             JdbcUtils.closeResultSet(rs);
143             JdbcUtils.closeStatement(ps);
144         }
145         return roleNames;
146     }
147 
148     protected Set<String> getPermissions(Connection conn, String username, Collection<String> roleNames) throws SQLException {
149         PreparedStatement ps = null;
150         Set<String> permissions = new LinkedHashSet<String>();
151         try {
152             ps = conn.prepareStatement(permissionsQuery);
153             for (String roleName : roleNames) {
154                 ps.setString(1, roleName);
155                 ResultSet rs = null;
156                 try {
157                     rs = ps.executeQuery();
158                     while (rs.next()) {
159                         String permissionString = rs.getString(1);
160                         String[] permissionNames = permissionString.split(",");
161                         permissions.addAll(Arrays.asList(permissionNames));
162                     }
163                 } finally {
164                     JdbcUtils.closeResultSet(rs);
165                 }
166             }
167         } finally {
168             JdbcUtils.closeStatement(ps);
169         }
170         return permissions;
171     }
172 }

MyJdbcRealm類就是從shiro中原有的JdbcRealm類copy來的,去掉了與密碼鹽(salt)有關的部分。

我在數據庫的權限表中添加的權限字段值為 “user:add,user:delete,user:update,user:select,user:updateRole” 的格式,而shiro中原有的JdbcRealm中會將這一長串當成一種權限來看,在 MyJdbcRealm 類中改寫了 JdbcRealm中的 getPermissions(Connection conn, String username, Collection<String> roleNames) 方法(具體看159-161行)來使權限字段的值為 5種 不同的權限。

    當然,你也可以在自定義的 Realm 類中重寫 doGetAuthorizationInfo(PrincipalCollection principals) 方法,來實現自己的權限管理。

 

  接着,編寫shiro的配置類(ShiroConfiguration)

 

  1 package com.hui.SpringBoot22;
  2 
  3 import com.hui.SpringBoot22.realm.MyJdbcRealm;
  4 import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
  5 import org.apache.shiro.mgt.SecurityManager;
  6 import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
  7 import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
  8 import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
  9 import org.springframework.beans.factory.annotation.Autowired;
 10 import org.springframework.beans.factory.annotation.Qualifier;
 11 import org.springframework.context.annotation.Bean;
 12 import org.springframework.context.annotation.Configuration;
 13 import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
 14 
 15 import javax.sql.DataSource;
 16 import java.util.*;
 17 
 18 @Configuration
 19 public class ShiroConfiguration {
 20 
 21     @Autowired
 22     private DataSource dataSource;
 23 
 24     @Bean(name = "shiroFilter")
 25     public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") SecurityManager securityManager){
 26         ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
 27         shiroFilterFactoryBean.setSecurityManager(securityManager);
 28         //配置login頁、登陸成功頁、沒有權限頁
 29         shiroFilterFactoryBean.setLoginUrl("/");
 30         shiroFilterFactoryBean.setSuccessUrl("/index");
 31         shiroFilterFactoryBean.setUnauthorizedUrl("/403");
 32 
 33         //配置訪問權限(順序執行攔截)
 34         //   “/**” 放到最下面,如果將("/**","authc")放到("/userLogin","anon")的上面
 35         //          則“/userLogin”可能會被攔截
 36         Map<String,String> filterChainDefinitionMap = new LinkedHashMap<>();
 37         filterChainDefinitionMap.put("/logout","logout");
 38         filterChainDefinitionMap.put("/userLogin","anon");
 39         filterChainDefinitionMap.put("/403","roles");
 40         filterChainDefinitionMap.put("/**","authc");
 41         shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
 42         return shiroFilterFactoryBean;
 43     }
 44 
 45     @Bean(name = "securityManager")
 46     public SecurityManager securityManager(@Qualifier("myJdbcRealm")MyJdbcRealm myJdbcRealm){
 47         DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
 48         securityManager.setRealm(myJdbcRealm);
 49         return securityManager;
 50     }
 51 
 52     @Bean(name = "myJdbcRealm")
 53     public MyJdbcRealm myJdbcRealm(@Qualifier("credentialsMatcher") HashedCredentialsMatcher credentialsMatcher,
 54                                  @Qualifier("dataSource") DataSource dataSource){
 55         MyJdbcRealm myJdbcRealm = new MyJdbcRealm();
 56         //打開shiro的權限  (默認為false)  (不開啟則不會檢查權限 --> 點擊“修改”,不管有沒有權限都能進行跳轉)
 57         myJdbcRealm.setPermissionsLookupEnabled(true);
 58         //設置datasource
 59         myJdbcRealm.setDataSource(dataSource);
 60         //設置密碼加密器
 61         myJdbcRealm.setCredentialsMatcher(credentialsMatcher);
 62         //設置登陸驗證sql語句
 63         String sql = "select password from test_user where username = ?";
 64         myJdbcRealm.setAuthenticationQuery(sql);
 65         //設置權限驗證sql語句
 66         String permissionSql = "select permission from permissions where role_name = ?";
 67         myJdbcRealm.setPermissionsQuery(permissionSql);
 68         return myJdbcRealm;
 69     }
 70 
 71     //設置加密算法為MD5。加密次數為1
 72     @Bean(name = "credentialsMatcher")
 73     public HashedCredentialsMatcher credentialsMatcher(){
 74         HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
 75         credentialsMatcher.setHashAlgorithmName("md5");
 76         credentialsMatcher.setHashIterations(1);
 77         return credentialsMatcher;
 78     }
 79 
 80     /**
 81      * 開啟aop注解支持 -- 借助SpringAOP掃描使用shiro注解的類
 82      *      (不開啟則不能掃描到shiro的@RequiresPermissions等注解)
 83      * @param securityManager
 84      * @return
 85      */
 86     @Bean
 87     public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
 88         AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
 89         authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
 90         return authorizationAttributeSourceAdvisor;
 91     }
 92 
 93     //配置無權限異常處理,跳轉到403
 94     @Bean(name="simpleMappingExceptionResolver")
 95     public SimpleMappingExceptionResolver
 96     createSimpleMappingExceptionResolver() {
 97         SimpleMappingExceptionResolver r = new SimpleMappingExceptionResolver();
 98         Properties mappings = new Properties();
 99         mappings.setProperty("DatabaseException", "databaseError");//數據庫異常處理
100         mappings.setProperty("UnauthorizedException", "403");
101         r.setExceptionMappings(mappings);  // None by default
102         r.setDefaultErrorView("error");    // No default
103         r.setExceptionAttribute("ex");     // Default is "exception"
104         return r;
105     }
106 
107 }

 

  上面代碼中有幾個需要注意的點:

第一點:是再定義的名為“securityManager”的 Bean 中,使用的是 DefaultWebSecurityManager 這個類,而不是 DefaultSecurityManager(使用DefaultSecurityManager類會報錯),前者是 org.apache.shiro.web.mgt 包下的,與web有關;后者是 org.apache.shiro.mgt 包下的。

第二點:開啟aop注解支持 -- 借助SpringAOP掃描使用shiro注解的類,開啟之后可以掃描到 Controller 類上的shiro注解(例如:@RequiresPermissions、@RequiresRoles等

第三點:配置無權限異常處理,這樣就會攔截到沒有權限的用戶,然后跳轉到403頁面(

  這里配置無權限異常處理是為了配合shiro注解。

  如果不想使用shiro注解,也可以不配置該異常處理,直接在攔截鏈“filterChainDefinitionMap”中配置 -- 例如:/userList= roles["admin","admin1"] --> 表明訪問路徑 /userList 需要同時具備“admin”和“admin1”的角色,不合條件則403;             另一種與角色攔截相似:權限攔截 -- /userList= perms["user:select"]

第四點:在名為 “myJdbcRealm” Bean中,設置登陸驗證與權限驗證的sql查詢語句,方法分別是 setAuthenticationQuery("select password from test_user where username = ?") 、 setPermissionsQuery("select permission from permissions where role_name = ?")  

之所以執行這兩個setXxx()方法,是因為我這里的實體類對應生成的表名、字段名與shiro默認的不一致(如果你想使用shiro默認的,那么你就需要按照shiro源碼中的sql語句來設置實體生成的表名、字段名與shiro默認的一致即可)

 

  接下來,編寫實體類

User類

 1 package com.hui.SpringBoot22.pojo;
 2 
 3 import javax.persistence.*;
 4 
 5 @Entity
 6 @Table(name = "test_user")
 7 public class User {
 8     @Id
 9     @GeneratedValue(strategy = GenerationType.IDENTITY)//默認為AUTO,這里設置為自增
10     private Long id;
11     @Column(name = "username",length = 50)
12     private String username;
13     @Column(name = "password",length = 50)
14     private String password;
15 
16     public Long getId() {
17         return id;
18     }
19 
20     public void setId(Long id) {
21         this.id = id;
22     }
23 
24     public String getUsername() {
25         return username;
26     }
27 
28     public void setUsername(String username) {
29         this.username = username;
30     }
31 
32     public String getPassword() {
33         return password;
34     }
35 
36     public void setPassword(String password) {
37         this.password = password;
38     }
39 }

 

Role類

 1 package com.hui.SpringBoot22.pojo;
 2 
 3 import javax.persistence.*;
 4 
 5 @Entity
 6 @Table(name = "user_roles")
 7 public class Role {
 8     @Id
 9     @GeneratedValue(strategy = GenerationType.IDENTITY)
10     private Long id;
11     @Column(name = "username",length = 50)
12     private String username;
13     @Column(name = "role_name",length = 50)
14     private String roles;
15 
16     public Long getId() {
17         return id;
18     }
19 
20     public void setId(Long id) {
21         this.id = id;
22     }
23 
24     public String getUsername() {
25         return username;
26     }
27 
28     public void setUsername(String username) {
29         this.username = username;
30     }
31 
32     public String getRoles() {
33         return roles;
34     }
35 
36     public void setRoles(String roles) {
37         this.roles = roles;
38     }
39 }
Permission類
 1 package com.hui.SpringBoot22.pojo;
 2 
 3 import javax.persistence.*;
 4 
 5 @Entity
 6 @Table(name = "permissions")
 7 public class Permission {
 8     @Id
 9     @GeneratedValue(strategy = GenerationType.IDENTITY)
10     private Long id;
11     @Column(name = "role_name",length = 50)
12     private String roleName;
13     @Column(name = "permission",length = 120)
14     private String permissions;
15 
16     public Long getId() {
17         return id;
18     }
19 
20     public void setId(Long id) {
21         this.id = id;
22     }
23 
24     public String getRoleName() {
25         return roleName;
26     }
27 
28     public void setRoleName(String roleName) {
29         this.roleName = roleName;
30     }
31 
32     public String getPermissions() {
33         return permissions;
34     }
35 
36     public void setPermissions(String permissions) {
37         this.permissions = permissions;
38     }
39 }

這里就不多說了,主要注意的就是對應的表名、字段名要與 ShiroConfiguration 類中的sql語句的表名、字段名一致。

 

  接下來是Repository編寫,直接看代碼好了

 

 1 package com.hui.SpringBoot22.repository;
 2 
 3 import com.hui.SpringBoot22.pojo.User;
 4 import org.springframework.data.jpa.repository.JpaRepository;
 5 import org.springframework.data.jpa.repository.Modifying;
 6 import org.springframework.data.jpa.repository.Query;
 7 
 8 import javax.transaction.Transactional;
 9 
10 public interface UserRepository extends JpaRepository<User,Long> {
11     User findUserById(Long id);
12 
13     @Transactional
14     @Modifying
15     @Query("update User set username=?2,password=?3 where id=?1")
16     int updateUserById(Long id,String username,String password);
17 
18     @Transactional
19     @Modifying
20     @Query("delete from User where id=?1")
21     void deleteUserById(Long id);
22 }

 

這里繼承了JpaRepository類,就不用再類上加Spring注解來將其注入(因為 JpaRepository 類上有一個@NoRepositoryBean注解,原理咱不懂!!!

select、delete之類的語句 Jpa 已經封裝了一部分方法,我們可以直接調用,如 save(S entity)、delete(T entity)等

如果Jpa中封裝的不能滿足需求,那就自己寫啦

  像上面的在 UserRepository 類中添加一個方法,然后再方法上加上@Query注解,里面有個value屬性,用來指定編寫的sql語句  -->  如:@Query(value="update ...")

值得注意的是,在 @Query 注解中的 sql 語句對應的表名應寫 實體類名(上面代碼中本人寫的就是實體類 User );關於sql中的字段是不是需要用實體類屬性名,有興趣的朋友可以自己試一下。

如果覺得別扭,可以在@Query注解中編寫 nativeQuery 屬性,使其值為 true ,這樣 Jpa 就能識別原生 sql 了   -->    

例子:  @Query(nativeQuery = true,
   value="select r.id,r.username,r.role_name from user_roles u left join user_roles r on u.username=r.username where u.id=?1")
     Role findRoleByUserid(Long id);

 

最后,如果是insert、delete、update之類的語句,還要在方法上面加上@Modifying和@Transactional注解等大佬幫我解惑ing...

 

  接着,再貼一下 controller 的代碼

 

 1 package com.hui.SpringBoot22.controller;
 2 
 3 import com.hui.SpringBoot22.pojo.User;
 4 import com.hui.SpringBoot22.repository.UserRepository;
 5 import com.hui.SpringBoot22.utils.Md5;
 6 import org.apache.shiro.SecurityUtils;
 7 import org.apache.shiro.authc.UsernamePasswordToken;
 8 import org.apache.shiro.authz.annotation.RequiresPermissions;
 9 import org.apache.shiro.subject.Subject;
10 import org.springframework.beans.factory.annotation.Autowired;
11 import org.springframework.stereotype.Controller;
12 import org.springframework.web.bind.annotation.RequestMapping;
13 
14 import java.util.List;
15 import java.util.Map;
16 
17 @Controller
18 public class UserController {
19     @Autowired
20     private UserRepository userRepository;
21 
22     @RequestMapping("/")
23     public String toLogin(){
24         return "login";
25     }
26 
27     @RequestMapping("/userLogin")
28     public String userLogin(String username, String password, Map<String,Object> map){
29         Subject subject = SecurityUtils.getSubject();
30         UsernamePasswordToken token = new UsernamePasswordToken(username,password);
31         try{
32             subject.login(token);
33             map.put("loginName",username);
34         }catch(Exception e){
35             map.put("msg","登陸失敗");
36             return "login";
37         }
38         return "forward:userList";
39     }
40 
41     @RequestMapping("/userList")
42     @RequiresPermissions("user:select")
43     public String list(Map<String,Object> map){
44         List<User> users = userRepository.findAll();
45         map.put("userList",users);
46         return "userList";
47     }
48 
49     @RequestMapping("/toUserAdd")
50     public String toAdd(){
51         return "userAdd";
52     }
53 
54     @RequestMapping("/userAdd")
55     @RequiresPermissions("user:add")
56     public String userAdd(User user){
57         user.setPassword(Md5.md5(user.getPassword()));
58         userRepository.save(user);
59         return "forward:userList";
60     }
61 
62     @RequestMapping("/toUserEdit")
63     public String toEdit(Long id,Map<String,Object> map){
64         User user = userRepository.findUserById(id);
65         map.put("user",user);
66         return "userEdit";
67     }
68 
69     @RequestMapping("/userEdit")
70     @RequiresPermissions("user:update")
71     public String userEdit(Long id,String username,String password){
72         password = Md5.md5(password);
73         userRepository.updateUserById(id,username,password);
74         return "forward:userList";
75     }
76 
77     @RequestMapping("/userDelete")
78     @RequiresPermissions("user:delete")
79     public String deleteUser(Long id){
80         userRepository.deleteUserById(id);
81         return "forward:userList";
82     }
83 }

@RequiresPermissions注解是驗證用戶權限

@RequiresRoles注解是驗證用戶角色(這個在RoleController中用到,這里沒有貼出來

 

  然后,再看一部分使用 thymeleaf 的HTML代碼

 

 1 <!DOCTYPE html>
 2 <html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6 </head>
 7 <body>
 8 <div style="margin-left: 30%">
 9     <form action="/roleUpdate" method="post">
10         <input type="hidden" name="id" th:value="${role.id}"/>
11         用  戶  名:<input name="username" type="text" th:value="${role.username}"/><br/><br/>
12         選擇角色:<input style="margin-left: 8px;" type="radio" name="roles"
13                     th:each="roleName,roleNameStat:${roleNameList}"
14                     th:value="${roleName}"
15                     th:text="${roleName}"
16                     th:attr="checked=${roleName==role.roles?true:false}"
17                     /><br/><br/>
18         <input type="submit" value="提交"/>
19     </form>
20 </div>
21 </body>
22 </html>

 

老實說,第一次使用 thymeleaf 真的不大習慣,總是寫成常規的 HTML 代碼

 

上面也沒什么好說的,也就一個下拉框的遍歷(

                      th:text 表示文本值, th:value 表示value值,th:attr 表示是否選中狀態,

                      th:each 就是遍歷后台傳來的 list 集合  -->  roleName 代表每一個 list 集合元素,roleNameStat.index 代表着該元素的下標

                      )

 

  最后,再看一下配置文件 application.properties

 1 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
 2 spring.datasource.url=jdbc:mysql://localhost:3306/xxx?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
 3 spring.datasource.username=xxx
 4 spring.datasource.password=xxx
 5 
 6 spring.jpa.hibernate.ddl-auto=create-drop
 7 spring.jpa.show-sql=true
 8 spring.jpa.database=mysql
 9 
10 spring.thymeleaf.cache=false
11 spring.thymeleaf.mode=HTML

這個地方有一個坑,就是如果我們設置 spring.jpa.hibernate.ddl-auto=update,就不會執行 resources 目錄下的 import.sql 文件等

根據官方文檔來說,如果需要執行 resources 目錄下的 import.sql 文件,就必須設置 spring.jpa.hibernate.ddl-auto 的值為 create 或者 create-drop

還一種辦法就是不使用 spring.jpa.hibernate.ddl-auto ,直接在 resources 目錄下添加 schema.sql 和 data.sql 文件(schema.sql用來執行DDL語句,data.sql用來執行DML語句)

 

  還有少部分代碼和 HTML 就不貼出來了,有興趣的可以去下載源代碼看看。

  項目默認登陸用戶   ==>   用戶名:lmh,密碼:123

  項目GitHub地址https://github.com/Lmh115/SpringBoot

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM