SpringBoot2.1.6 + Shiro1.4.1 + Thymeleaf + Jpa整合练习

Stella981
• 阅读 573

  首先,添加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 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

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Easter79 Easter79
3年前
springboot2.1整合mybatis
1:添加依赖<?xmlversion"1.0"encoding"UTF8"?<projectxmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchemainstance"xsi
Stella981 Stella981
3年前
SpringBoot2.0配置durid数据源
pom依赖<?xmlversion"1.0"encoding"UTF8"?<projectxmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchemainstance"
Stella981 Stella981
3年前
121 项目 034 笔记向 easyui
pom<?xmlversion"1.0"encoding"UTF8"?<projectxmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchemainstance"
可莉 可莉
3年前
121 项目 034 笔记向 easyui
pom<?xmlversion"1.0"encoding"UTF8"?<projectxmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchemainstance"
Easter79 Easter79
3年前
SpringBoot2.1.6 + Shiro1.4.1 + Thymeleaf + Jpa整合练习
  首先,添加maven依赖,完整的pom文件如下:1<?xmlversion"1.0"encoding"UTF8"?2<projectxmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema
Easter79 Easter79
3年前
SpringBoot2.0配置durid数据源
pom依赖<?xmlversion"1.0"encoding"UTF8"?<projectxmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchemainstance"
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这