Springboot 系列 (4) - 在 Spring Boot 项目里使用 Spring Security、Druid 和 MyBatis

 

Spring Security 是一个功能强大且高度可定制的身份验证和访问控制框架。Spring Boot 给 Spring Security 提供了自动化配置方案 (spring-boot-starter-security),可以零配置使用 Spring Security。

Druid 是阿里巴巴推出的一款开源的高性能数据源产品,Druid 支持所有 JDBC 兼容的数据库,包括 Oracle、MySQL、SQL Server 和 H2 等等。Druid 不仅结合了 C3P0、DBCP 和 PROXOOL 等数据源产品的优点,同时还加入了强大的监控功能。通过 Druid 的监控功能,可以实时观察数据库连接池和 SQL 的运行情况,帮助用户及时排查出系统中存在的问题。

Druid GitHub: https://github.com/alibaba/druid

MyBatis 是一个半自动化的 ORM 框架,所谓半自动化是指 MyBatis 只支持将数据库查出的数据映射到 POJO 实体类上,而实体到数据库的映射则需要我们自己编写 SQL 语句实现,相较于Hibernate 这种完全自动化的框架,Mybatis 更加灵活,我们可以根据自身的需求编写 SQL 语句来实现复杂的数据库操作。

MyBatis 也开发了一套基于 Spring Boot 模式的 starter:mybatis-spring-boot-starter。

MyBatis GitHub: https://github.com/mybatis


1. 开发环境

    Windows版本:Windows 10 Home (20H2)   
    IntelliJ IDEA (https://www.jetbrains.com/idea/download/):Community Edition for Windows 2020.1.4
    Apache Maven (https://maven.apache.org/):3.8.1

    注:Spring 开发环境的搭建,可以参考 “ Spring基础知识(1)- Spring简介、Spring体系结构和开发环境配置 ”。


2. 创建 Spring Boot 基础项目

    项目实例名称:SpringbootExample04
    Spring Boot 版本:2.6.6

    创建步骤:

        (1) 创建 Maven 项目实例 SpringbootExample04;
        (2) Spring Boot Web 配置;
        (3) 导入 Thymeleaf 依赖包;
        (4) 配置静态资源(jQuery、Bootstrap、Images);
        
    具体操作请参考 “Springboot 系列 (2) - 在 Spring Boot 项目里使用 Thymeleaf、JQuery+Bootstrap 和国际化” 里的项目实例 SpringbootExample02,文末包含如何使用 spring-boot-maven-plugin 插件运行打包的内容。

    SpringbootExample04 和 SpringbootExample02 相比,SpringbootExample04 不包含 Thymeleaf 模版文件(templates/*.htm l)和国际化。


3. 配置 Spring security

    1)  修改 pom.xml,导入 Spring security 依赖包

复制代码
 1         <project ... >
 2             ...
 3             <dependencies>
 4                 ...
 5 
 6                 <!-- Spring security -->
 7                 <dependency>
 8                     <groupId>org.springframework.boot</groupId>
 9                     <artifactId>spring-boot-starter-security</artifactId>
10                 </dependency>
11 
12                 ...
13             </dependencies>
14 
15             ...
16         </project>
复制代码


        在IDE中项目列表 -> SpringbootExample04 -> 点击鼠标右键 -> Maven -> Reload Project

    2) 修改 src/main/resources/application.properties 文件,添加如下配置

        # security
        spring.security.user.name=admin
        spring.security.user.password=123456
        spring.security.user.roles=admin

        运行并访问 http://localhost:9090/test,自动跳转到 http://localhost:9090/login (Spring security 的默认页面),输入上面的用户名和密码登录,登录后跳转到 http://localhost:9090/test。

  注:如果不在 application.properties 里配置 admin, 默认用户名是 user,密码在项目启动时输出在控制台,格式如下:

    Using generated security password: 61c29bfd-0f2b-4a35-a27c-c569f9b6f02d

    This generated password is for development use only. Your security configuration must be updated before running your application in production.

  配置 admin 后,默认用户 user 将失效。


    3) 创建 src/main/resources/templates/common.html 文件

复制代码
 1         <div th:fragment="header(var)">
 2             <meta charset="UTF-8">
 3             <title th:text="${var}">Title</title>
 4             <link rel="stylesheet" th:href="@{/lib/bootstrap-4.2.1-dist/css/bootstrap.min.css}" href="/lib/bootstrap-4.2.1-dist/css/bootstrap.min.css">
 5             <script language="javascript" th:src="@{/lib/jquery/jquery-3.6.0.min.js}" src="/lib/jquery/jquery-3.6.0.min.js"></script>
 6             <script language="javascript" th:src="@{/lib/bootstrap-4.2.1-dist/js/bootstrap.min.js}" src="/lib/bootstrap-4.2.1-dist/js/bootstrap.min.js"></script>
 7         </div>
 8 
 9         <div th:fragment="content-header" class="container" id="content-header-id">
10             <nav class="navbar navbar-light bg-light">
11                 <a class="navbar-brand" href="#">
12                     <img th:src="@{/images/bootstrap-solid.svg}" src="/images/bootstrap-solid.svg" width="30" height="30" class="d-inline-block align-top" alt="">
13                     Thymeleaf Demo
14                 </a>
15 
16                 <a class="nav-link" th:href="@{/logout}" th:if="${session.loginUser} != null">Logout</a>
17             </nav>
18         </div>
19 
20         <div th:fragment="content-footer(var)" class="container" id="content-footer-id">
21             <p th:text="${var}">Content Footer</p>
22         </div>
复制代码


    4) 创建 src/main/resources/templates/login.html 文件

复制代码
 1         <!DOCTYPE html>
 2         <html lang="en" xmlns:th="http://www.thymeleaf.org">
 3         <head th:include="common::header(var='Login')">
 4         </head>
 5         <body>
 6         <div th:replace="common::content-header"></div>
 7 
 8         <div class="container" id="content" th:style="'min-height: 480px;'">
 9             <h4>Login</h4>
10 
11             <p>&nbsp;</p>
12             <div class="alert alert-info" role="alert" th:text="${message}" th:if ="${message} != null"></div>
13 
14             <form method="POST" action="/login/post">
15                 <div class="form-group">
16                     <label for="username">Username</label>
17                     <input type="text" class="form-control" id="username" name="username" value="admin" />
18                 </div>
19                 <div class="form-group">
20                     <label for="password">Password</label>
21                     <input type="password" class="form-control" id="password" name="password" value="123456" />
22                 </div>
23                 <button type="submit" class="btn btn-primary">Submit</button>
24             </form>
25 
26         </div>
27 
28         <div th:replace="common::content-footer(var='Copyright &copy; 2020')"></div>
29 
30         <script type="text/javascript">
31                 $(document).ready(function(){
32                     console.log("jQuery is running");
33                 });
34             </script>
35         </body>
36         </html>
复制代码


    5) 创建 src/main/resources/templates/home.html 文件

复制代码
 1         <!DOCTYPE html>
 2         <html lang="en" xmlns:th="http://www.thymeleaf.org">
 3         <head th:include="common::header(var='Home')">
 4         </head>
 5         <body>
 6             <div th:replace="common::content-header"></div>
 7 
 8             <div class="container" id="content" th:style="'min-height: 480px;'">
 9                 <h4>Home Page</h4>
10 
11                 <p>&nbsp;</p>
12                 <div class="alert alert-info" role="alert" th:text="${message}" th:if ="${message} != null"></div>
13             </div>
14 
15             <div th:replace="common::content-footer(var='Copyright &copy; 2020')"></div>
16 
17             <script type="text/javascript">
18                 $(document).ready(function(){
19                     console.log("jQuery is running");
20                 });
21             </script>
22         </body>
23         </html>
复制代码


    6) 修改 src/main/java/com/example/controller/IndexController.java 文件

复制代码
 1         package com.example.controller;
 2 
 3         import org.springframework.ui.Model;
 4         import org.springframework.stereotype.Controller;
 5         import org.springframework.web.bind.annotation.RequestMapping;
 6         import org.springframework.web.bind.annotation.ResponseBody;
 7 
 8         @Controller
 9         public class IndexController {
10             @ResponseBody
11             @RequestMapping("/test")
12             public String test() {
13                 return "Test Page";
14             }
15 
16             @RequestMapping("/home")
17             public String home(Model model) {
18                 model.addAttribute("message", "Spring Boot Login Demo");
19                 return "home";
20             }
21 
22             @RequestMapping("/login")
23             public String login() {
24                 return "login";
25             }
26         }
复制代码


    7) 创建 src/main/java/com/example/config/WebSecurityConfig.java 文件

复制代码
 1         package com.example.config;
 2 
 3         import org.springframework.beans.factory.annotation.Autowired;
 4         import org.springframework.context.annotation.Configuration;
 5         import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
 6         import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 7         import org.springframework.security.core.userdetails.UserDetailsService;
 8         import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
 9 
10         @Configuration
11         public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
12             @Autowired
13             private UserDetailsService userDetailsService;
14 
15             @Override
16             protected void configure(AuthenticationManagerBuilder auth) throws Exception {
17                 auth.userDetailsService(userDetailsService);
18             }
19 
20             @Override
21             protected void configure(HttpSecurity http) throws Exception {
22                 // 配置认证
23                 http.authorizeRequests()
24                     .antMatchers("/lib/**").permitAll()
25                     .antMatchers("/images/**").permitAll()
26                     .antMatchers("/error").permitAll()
27                     .antMatchers("/**/*.html").permitAll()
28                     .anyRequest().authenticated()
29 
30                     .and()
31                     .formLogin()
32                     .loginPage("/login") // 自定义登录页面
33                     .loginProcessingUrl("/login/post") // 登录访问路径
34                     .defaultSuccessUrl("/home").permitAll()    // 登陆成功之后跳转地址
35 
36                     .and()
37                     .csrf().disable(); // 关闭 csrf 保护功能,默认是开启的
38 
39             }
40 
41         }
复制代码


        运行并访问 http://localhost:9090/home,自动跳转到 http://localhost:9090/login (Spring security 的默认页面),输入上面的用户名和密码,登录后跳转到 http://localhost:9090/home。


4. 配置 Druid

    1) 修改 pom.xml,导入 MariaDB、JDBC、Druid 依赖包

复制代码
 1         <project ... >
 2             ...
 3             <dependencies>
 4                 ...
 5 
 6                 <!-- MariaDB -->
 7                 <dependency>
 8                     <groupId>org.mariadb.jdbc</groupId>
 9                     <artifactId>mariadb-java-client</artifactId>
10                 </dependency>
11                 <!-- JDBC -->
12                 <dependency>
13                     <groupId>org.springframework.boot</groupId>
14                     <artifactId>spring-boot-starter-data-jdbc</artifactId>
15                 </dependency>
16                 <!-- Druid -->
17                 <dependency>
18                     <groupId>com.alibaba</groupId>
19                     <artifactId>druid</artifactId>
20                     <version>1.2.8</version>
21                 </dependency>
22 
23                 ...
24             </dependencies>
25 
26             ...
27         </project>
复制代码


        在IDE中项目列表 -> SpringbootExample04 -> 点击鼠标右键 -> Maven -> Reload Project

    2) 创建 src/main/java/com/example/config/DruidDataSourceConfig.java 文件

复制代码
 1         package com.example.config;
 2 
 3         import javax.sql.DataSource;
 4         import java.sql.SQLException;
 5 
 6         import com.alibaba.druid.pool.DruidDataSource;
 7         import org.springframework.boot.context.properties.ConfigurationProperties;
 8         import org.springframework.context.annotation.Bean;
 9         import org.springframework.context.annotation.Configuration;
10         import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
11 
12         @Configuration
13         public class DruidDataSourceConfig implements WebMvcConfigurer {
14 
15             @ConfigurationProperties("spring.datasource")
16             @Bean
17             public DataSource dataSource() throws SQLException {
18                 DruidDataSource druidDataSource = new DruidDataSource();
19                 return druidDataSource;
20             }
21         }
复制代码


    3) 修改 src/main/resources/application.properties 文件,添加如下代码:

1         # 数据源连接信息
2         spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
3         spring.datasource.url=jdbc:mysql://localhost:3306/springboot_example
4         spring.datasource.username=root
5         spring.datasource.password=123456


    4) 修改 src/main/java/com/example/controller/IndexController.java 文件

复制代码
 1         package com.example.controller;
 2 
 3         import java.sql.SQLException;
 4         import javax.sql.DataSource;
 5         import org.springframework.beans.factory.annotation.Autowired;
 6 
 7         import org.springframework.ui.Model;
 8         import org.springframework.stereotype.Controller;
 9         import org.springframework.web.bind.annotation.RequestMapping;
10         import org.springframework.web.bind.annotation.ResponseBody;
11 
12         @Controller
13         public class IndexController {
14             @Autowired
15             DataSource dataSource;
16 
17             ...
18  
19             @ResponseBody
20             @RequestMapping("/druid")
21             public String druid() throws SQLException {
22                 String str = "Druid Page<br><br>";             
23                 str += "DataSource:" + dataSource.getClass() + "<br>";
24                 str += "DataSource Connection:" + dataSource.getConnection() + "<br>";
25                 return str;
26             }
27         }
复制代码


        运行并访问 http://localhost:9090/druid,登录后,页面显示类似如下内容就表示 Druid 设置成功。

            Druid Page

            DataSource:class com.alibaba.druid.pool.DruidDataSource
            DataSource Connection:org.mariadb.jdbc.MariaDbConnection@3fc45e93

        注:如何开启 Druid 内置监控页面,请参考 “Springboot基础知识(15)- 整合 Druid 数据源” 的整合 Druid 数据源。


5. 配置数据库(MariaDB)

    1) XAMPP for Windows

        https://www.apachefriends.org/download.html
        
        本文安装版本 7.4.25,用到 XAMPP 的如下功能:

            + Apache 2.4.51
            + MariaDB 10.4.21 (MySQL的分支)
            + PHP 7.4.25 (VC15 X86 64bit thread safe) + PEAR
            + phpMyAdmin 5.1.1

    2) 创建数据库 springboot_example 和 user 表,SQL 脚本如下

复制代码
 1         CREATE TABLE `user` (
 2             `id` int(11) NOT NULL,
 3             `username` varchar(50) NOT NULL,
 4             `password` varchar(255) DEFAULT NULL,
 5             `age` int(11) DEFAULT NULL,
 6             `createtime` timestamp NULL DEFAULT NULL
 7         ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 8 
 9         ALTER TABLE `user` ADD PRIMARY KEY (`id`);
10 
11         ALTER TABLE `user` MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
12 
13         INSERT INTO `user` (`id`, `username`, `password`, `age`, `createtime`) VALUES
14         (1, 'admin', 'admin', 21, '2020-01-01 01:01:01'),(2, 'test', 'test', 28, '2020-02-02 02:02:02');
复制代码


    3)创建 src/main/java/com/example/entity/User.java 文件

复制代码
 1         package com.example.entity;
 2 
 3         import java.util.Date;
 4 
 5         public class User {
 6             private Integer id;
 7             private String username;
 8             private String password;
 9             private Integer age;
10             private Date createtime;
11 
12             public User() {
13 
14             }
15 
16             public Integer getId() {
17                 return id;
18             }
19             public void setId(Integer id) {
20                 this.id = id;
21             }
22 
23             public String getUsername() {
24                 return username;
25             }
26             public void setName(String username) {
27                 this.username = username;
28             }
29 
30             public String getPassword() {
31                 return password;
32             }
33             public void setPassword(String password) {
34                 this.password = password;
35             }
36 
37             public Integer getAge() {
38                 return age;
39             }
40             public void setAge(Integer age) {
41                 this.age = age;
42             }
43 
44             public Date getCreatetime() {
45                 return createtime;
46             }
47             public void setCreatetime(Date createtime) {
48                 this.createtime = createtime;
49             }
50 
51             @Override
52             public String toString() {
53                 return "User {" +
54                         "username = " + username +
55                         ", password = " + password +
56                         ", age = " + age +
57                         ", createtime = " + createtime +
58                         '}';
59             }
60         }
复制代码

 

6. 配置 MyBatis

    1)修改 pom.xml,导入 MyBatis 依赖包

复制代码
 1         <project ... >
 2             ...
 3             <dependencies>
 4                 ...
 5 
 6                 <!-- MyBatis -->
 7                 <dependency>
 8                     <groupId>org.mybatis.spring.boot</groupId>
 9                     <artifactId>mybatis-spring-boot-starter</artifactId>
10                     <version>2.2.0</version>
11                 </dependency>
12 
13                 ...
14             </dependencies>
15 
16             ...
17         </project>
复制代码


        在IDE中项目列表 -> SpringbootExample04 -> 点击鼠标右键 -> Maven -> Reload Project

    2) 修改 src/main/resources/application.properties 文件,添加如下代码:

        # mybatis
        mybatis.type-aliases-package=com.example
        mybatis.configuration.map-underscore-to-camel-case=true

    3)创建 src/main/java/com/example/mapper/UserMapper.java 文件

复制代码
 1         package com.example.mapper;
 2 
 3         import org.apache.ibatis.annotations.Mapper;
 4         import org.apache.ibatis.annotations.Select;
 5         import org.apache.ibatis.annotations.Param;
 6 
 7         import com.example.entity.User;
 8 
 9         @Mapper
10         public interface UserMapper {
11             
12             @Select("SELECT * FROM user WHERE username = #{username}")
13             User getUserByName(@Param("username") String username);
14 
15         }
复制代码


    4) 修改 src/main/java/com/example/controller/IndexController.java 文件

复制代码
 1         package com.example.controller;
 2 
 3         import java.sql.SQLException;
 4         import javax.sql.DataSource;
 5         import org.springframework.beans.factory.annotation.Autowired;
 6 
 7         import org.springframework.ui.Model;
 8         import org.springframework.stereotype.Controller;
 9         import org.springframework.web.bind.annotation.RequestMapping;
10         import org.springframework.web.bind.annotation.ResponseBody;
11 
12         import com.example.entity.User;
13         import com.example.mapper.UserMapper;
14 
15         @Controller
16         public class IndexController {
17             @Autowired
18             DataSource dataSource;
19             @Autowired
20             private UserMapper userMapper;
21 
22             ...
23  
24             @ResponseBody
25             @RequestMapping("/mybatis")
26             public String mybatis() throws SQLException {
27                 User user = userMapper.getUserByName("test");
28                 String str = "MyBatis Page<br><br>";             
29                 str += user + "<br>";
30                 return str;
31             }
32         }
复制代码


        运行并访问 http://localhost:9090/mybatis,登录后,页面显示类似如下内容就表示 MyBatis 设置成功。

            MyBatis Page

            User {username = test, password = test, age = 21, createtime = Wed Jan 01 01:01:01 CST 2020}


7.  把 MyBatis 用户数据整合到 Security 的用户验证

    1) 创建 src/main/java/com/example/service/MyUserDetailsService.java 文件

复制代码
 1         package com.example.service;
 2 
 3         import java.util.List;
 4         import java.util.ArrayList;
 5 
 6         import org.springframework.beans.factory.annotation.Autowired;
 7         import org.springframework.security.core.userdetails.User;
 8         import org.springframework.security.core.userdetails.UserDetails;
 9         import org.springframework.security.core.userdetails.UserDetailsService;
10         import org.springframework.security.core.userdetails.UsernameNotFoundException;
11         import org.springframework.security.core.GrantedAuthority;
12 
13         import com.example.mapper.UserMapper;
14 
15         public class MyUserDetailsService implements UserDetailsService {
16             @Autowired
17             private UserMapper userMapper;
18 
19             @Override
20             public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
21 
22                 com.example.entity.User user = userMapper.getUserByName(username);
23 
24                 List<GrantedAuthority> authorities = new ArrayList<>();
25 
26                 User userDetails= new User(user.getUsername(), user.getPassword(), authorities);
27                 return userDetails;
28             }
29         }
复制代码


    2) 修改 src/main/java/com/example/config/WebSecurityConfig.java 文件

复制代码
 1         package com.example.config;
 2 
 3         import org.springframework.beans.factory.annotation.Autowired;
 4         import org.springframework.context.annotation.Configuration;
 5         import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
 6         import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 7         //import org.springframework.security.core.userdetails.UserDetailsService;
 8         import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
 9 
10         import org.springframework.context.annotation.Bean;
11         import org.springframework.security.crypto.password.NoOpPasswordEncoder;
12         import org.springframework.security.crypto.password.PasswordEncoder;
13         import com.example.service.MyUserDetailsService;
14 
15         @Configuration
16         public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
17             @Autowired
18             //private UserDetailsService userDetailsService;
19             private MyUserDetailsService userDetailsService;
20 
21             // 数据库用明文密码,所以需要 NoOpPasswordEncoder 编码器
22             @Bean
23             public PasswordEncoder passwordEncoder(){
24                 return NoOpPasswordEncoder.getInstance();
25             }
26 
27             @Override
28             protected void configure(AuthenticationManagerBuilder auth) throws Exception {
29                 //auth.userDetailsService(userDetailsService);
30                 auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
31             }
32 
33             ...
34 
35         }
复制代码


        运行并访问 http://localhost:9090/test,自动跳转到 http://localhost:9090/login。注意:这里要输入数据库里的用户名和密码(admin/admin 或 test/test),登录成功后显示 http://localhost:9090/test 页面。


posted @   垄山小站  阅读(958)  评论(3编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 上周热点回顾(2.17-2.23)
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 如何使用 Uni-app 实现视频聊天(源码,支持安卓、iOS)
点击右上角即可分享
微信分享提示