当前位置:   article > 正文

18.SpringBoot框架二_htpp://127.0.0.1:8080/tologin

htpp://127.0.0.1:8080/tologin

十二 、集成SpringSecurity

文档:https://docs.spring.io/spring-security/site/docs/5.2.0.RELEASE/reference/htmlsingle/


认识SpringSecurity
Spring Security 是针对Spring项目的安全框架,也是Spring Boot底层安全模块默认的技术选型,他可以实现强大的Web安全控制,对于安全控制,我们仅需要引入 spring-boot-starter-security 模块,进行少量的配置,即可实现强大的安全管理!

记住几个类:

WebSecurityConfigurerAdapter:自定义Security策略

AuthenticationManagerBuilder:自定义认证策略

@EnableWebSecurity:开启WebSecurity模式

Spring Security的两个主要目标是 “认证” 和 “授权”(访问控制)。

“认证”(Authentication)

身份验证是关于验证您的凭据,如用户名/用户ID和密码,以验证您的身份。

身份验证通常通过用户名和密码完成,有时与身份验证因素结合使用。

 “授权” (Authorization)

授权发生在系统成功验证您的身份后,最终会授予您访问资源(如信息,文件,数据库,资金,位置,几乎任何内容)的完全权限。

这个概念是通用的,而不是只在Spring Security 中存在。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

1. 搭建环境

項目資源:https://gitee.com/ENNRIAAA/spring-security-material

1. 创建项目

项目名称:springboot-06-security

在这里插入图片描述
选择项目依赖
在这里插入图片描述
pom.xml导入依赖


          <!--thymeleaf模板-->
        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf-spring5</artifactId>
        </dependency>
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-java8time</artifactId>
        </dependency>
          <!--security-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

2. 导入静态资源

路径:https://spring.io/projects/spring-security
解压:
在这里插入图片描述
复制到项目resource里面
在这里插入图片描述

3. 编写控制器

路径: src/main/java/com/xxx/controller/RouterController.java
代码:

package com.xxx.controller;

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

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

    @RequestMapping("/toLogin")
    public String toLogin(){
        return "views/login";
    }

    @RequestMapping("/level1/{id}")
    public String level1(@PathVariable("id") int id){
        return "views/level1/"+id;
    }

    @RequestMapping("/level2/{id}")
    public String level2(@PathVariable("id") int id){
        return "views/level2/"+id;
    }

    @RequestMapping("/level3/{id}")
    public String level3(@PathVariable("id") int id){
        return "views/level3/"+id;
    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

运行:http://localhost:8080/
在这里插入图片描述

4. 配置

文档:https://docs.spring.io/spring-security/site/docs/5.2.0.RELEASE/reference/htmlsingle/
查看 15. Java Configuration 配置流程
在这里插入图片描述

1. 自定义配置

文档路径:https://docs.spring.io/spring-security/site/docs/5.2.0.RELEASE/reference/htmlsingle/#jc-custom-dsls
在这里插入图片描述

1. 创建控制器

路径:src/main/java/com/xxx/config/SecurityConfig.java
代码:

package com.xxx.config;

import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    //授权
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //首页所有人可以访问,功能页只有对应有权限的人才能访问
        //请求授权的规则
        // 定制请求的授权规则
        // 首页所有人可以访问
        http.authorizeRequests().antMatchers("/").permitAll()
                .antMatchers("/level1/**").hasRole("vip1")
                .antMatchers("/level2/**").hasRole("vip2")
                .antMatchers("/level3/**").hasRole("vip3");
        //没有权限跳转到登录页面,需要开启登录的页面
        http.formLogin();
        //注销,开启了注销功能
        http.logout().logoutSuccessUrl("/");
    }

    // 认证
    //密码编码:passwordEncoder
    //在spring se
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //super.configure(auth);
        //在内存中定义,也可以在jdbc中去拿....
        //Spring security 5.0中新增了多种加密方式,也改变了密码的格式。
        //要想我们的项目还能够正常登陆,需要修改一下configure中的代码。我们要将前端传过来的密码进行某种方式加密
        //spring security 官方推荐的是使用bcrypt加密方式。
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                .withUser("fj").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2", "vip3")
                .and()
                .withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1", "vip2", "vip3")
                .and()
                .withUser("guest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1", "vip2");

    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
2. 添加注销按钮

路径:src/main/resources/templates/index.html
代码:

 <div class="ui segment" id="index-header-nav" th:fragment="nav-menu">
        <div class="ui secondary menu">
            <a class="item"  th:href="@{/index}">首页</a>

            <!--登录注销-->
            <div class="right menu">
                <!--未登录-->
                <a class="item" th:href="@{/toLogin}">
                    <i class="address card icon"></i> 登录
                </a>
                <!--注销-->
                <a class="item" th:href="@{/logout}">
                    <i class="address card icon"></i> 注销
                </a>
                <!--已登录
                <a th:href="@{/usr/toUserCenter}">
                    <i class="address card icon"></i> admin
                </a>
                -->
            </div>
        </div>
    </div>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
3. 测试

访问:http://127.0.0.1:8080/
在这里插入图片描述
点击任何一个链接都跳转到登录http://127.0.0.1:8080/login
在这里插入图片描述
输入配置的用户名密码,登录,跳转到刚才点击的页面http://127.0.0.1:8080/level1/1
在这里插入图片描述
点击注销按钮注销
在这里插入图片描述

点击注销后跳转到:http://127.0.0.1:8080/logout
在这里插入图片描述
点击Log Out 返回首页
在这里插入图片描述

5. thymeleaf和security整合

我们现在又来一个需求:用户没有登录的时候,导航栏上只显示登录按钮,用户登录之后,导航栏可以显示登录的用户信息及注销按钮!还有就是,比如kuangshen这个用户,它只有 vip2,vip3功能,那么登录则只显示这两个功能,而vip1的功能菜单不显示!这个就是真实的网站情况了!该如何做呢?

我们需要结合thymeleaf中的一些功能
sec:authorize="isAuthenticated()":是否认证登录!来显示不同的页面

1. 导入包

<!-- https://mvnrepository.com/artifact/org.thymeleaf.extras/thymeleaf-extras-springsecurity4 -->
<dependency>
   <groupId>org.thymeleaf.extras</groupId>
   <artifactId>thymeleaf-extras-springsecurity5</artifactId>
   <version>3.0.4.RELEASE</version>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

2. 前端页面修改

路径:src/main/resources/templates/index.html

1. 导入命名空间
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
  • 1
  • 2
  • 3
2. 修改导航栏,增加认证判断
  <!--登录注销-->
      <div class="right menu">

       <!--如果未登录:显示登录-->
       <!--未登录-->
       <div sec:authorize="!isAuthenticated()">
            <a class="item" th:href="@{/toLogin}">
               <i class="address card icon"></i> 登录
            </a>
       </div>

      <!--如果登录:显示用户名-->
      <div sec:authorize="isAuthenticated()">
           <a class="item">
              用户名:<span sec:authentication="name"></span>
              角色:<span sec:authentication="principal.authorities"></span>
            </a>
      </div>
      <!--如果登录:显示注销-->
     <div sec:authorize="isAuthenticated()">
          <!--注销-->
          <a class="item" th:href="@{/logout}">
             <i class="address card icon"></i> 注销
          </a>
     </div>
            
  </div>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

3. 测试

访问:http://localhost:8080/,登录成功后
在这里插入图片描述

4. 关闭csrf功能

路径:src/main/java/com/xxx/config/SecurityConfig.java
代码:

http.csrf().disable();//关闭csrf功能:跨站请求伪造,默认只能通过post方式提交logout请求
http.logout().logoutSuccessUrl("/");
  • 1
  • 2

5. 角色功能块认证

根据当前登录的角色,显示角色能看的范围

1. 实现

路径:src/main/resources/templates/index.html
代码:

 <div>
        <br>
        <div class="ui three column stackable grid">
            <!--动态菜单的实现 sec:authorize="hasRole('vip1')"-->
            <div class="column" sec:authorize="hasRole('vip1')">
                <div class="ui raised segment">
                    <div class="ui">
                        <div class="content">
                            <h5 class="content">Level 1</h5>
                            <hr>
                            <div><a th:href="@{/level1/1}"><i class="bullhorn icon"></i> Level-1-1</a></div>
                            <div><a th:href="@{/level1/2}"><i class="bullhorn icon"></i> Level-1-2</a></div>
                            <div><a th:href="@{/level1/3}"><i class="bullhorn icon"></i> Level-1-3</a></div>
                        </div>
                    </div>
                </div>
            </div>

            <div class="column" sec:authorize="hasRole('vip2')">
                <div class="ui raised segment">
                    <div class="ui">
                        <div class="content">
                            <h5 class="content">Level 2</h5>
                            <hr>
                            <div><a th:href="@{/level2/1}"><i class="bullhorn icon"></i> Level-2-1</a></div>
                            <div><a th:href="@{/level2/2}"><i class="bullhorn icon"></i> Level-2-2</a></div>
                            <div><a th:href="@{/level2/3}"><i class="bullhorn icon"></i> Level-2-3</a></div>
                        </div>
                    </div>
                </div>
            </div>

            <div class="column" sec:authorize="hasRole('vip3')">
                <div class="ui raised segment">
                    <div class="ui">
                        <div class="content">
                            <h5 class="content">Level 3</h5>
                            <hr>
                            <div><a th:href="@{/level3/1}"><i class="bullhorn icon"></i> Level-3-1</a></div>
                            <div><a th:href="@{/level3/2}"><i class="bullhorn icon"></i> Level-3-2</a></div>
                            <div><a th:href="@{/level3/3}"><i class="bullhorn icon"></i> Level-3-3</a></div>
                        </div>
                    </div>
                </div>
            </div>

        </div>
    </div>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
2. 测试
  1. root登录http://localhost:8080/login
    在这里插入图片描述
    登录后
    在这里插入图片描述
  2. fj 登录:http://localhost:8080/login
    在这里插入图片描述
    登录后
    在这里插入图片描述

6. 记住我

现在的情况,我们只要登录之后,关闭浏览器,再登录,就会让我们重新登录,但是很多网站的情况,就是有一个记住密码的功能,这个该如何实现呢?很简单

1. 实现

路径:src/main/java/com/xxx/config/SecurityConfig.java
代码:

  //防止网站工具:get,post
        http.csrf().disable();//关闭csrf功能:跨站请求伪造,默认只能通过post方式提交logout请求
        //注销,开启了注销功能
        http.logout().logoutSuccessUrl("/");
        //记住我
        http.rememberMe();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
2. 测试

我们再次启动项目测试一下,发现登录页多了一个记住我功能,我们登录之后关闭 浏览器,然后重新打开浏览器访问,发现用户依旧存在!
访问路径:http://localhost:8080/login
在这里插入图片描述
思考:如何实现的呢?其实非常简单

我们可以查看浏览器的cookie
在这里插入图片描述
我们点击注销的时候,可以发现,spring security 帮我们自动删除了这个 cookie
在这里插入图片描述
结论:登录成功后,将cookie发送给浏览器保存,以后登录带上这个cookie,只要通过检查就可以免登录了。如果点击注销,则会删除这个cookie,具体的原理我们在JavaWeb阶段都讲过了,这里就不在多说了!

7. 定制登录页

现在这个登录页面都是spring security 默认的,怎么样可以使用我们自己写的Login界面呢?

1. 指定 loginpage

路径:src/main/java/com/xxx/config/SecurityConfig.java
代码:

http.formLogin().loginPage("/toLogin");

  • 1
  • 2
2. 定义的 login请求

路径:src/main/resources/templates/index.html
代码:

  <!--未登录-->
  <div sec:authorize="!isAuthenticated()">
       <a class="item" th:href="@{/toLogin}">
       <i class="address card icon"></i> 登录 </a>
 </div>
  • 1
  • 2
  • 3
  • 4
  • 5
3. 配置页面提交地址

我们登录,需要将这些信息发送到哪里,我们也需要配置,login.html 配置提交请求及方式,方式必须为post:
路径:src/main/resources/templates/views/login.html
代码:

<form th:action="@{/login}" method="post">
   <div class="field">
       <label>Username</label>
       <div class="ui left icon input">
           <input type="text" placeholder="Username" name="username">
           <i class="user icon"></i>
       </div>
   </div>
   <div class="field">
       <label>Password</label>
       <div class="ui left icon input">
           <input type="password" name="password">
           <i class="lock icon"></i>
       </div>
   </div>
   <input type="submit" class="ui blue submit button"/>
</form>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
4. 验证处理参数

这个请求提交上来,我们还需要验证处理,怎么做呢?我们可以查看formLogin()方法的源码!我们配置接收登录的用户名和密码的参数!
路径:src/main/java/com/xxx/config/SecurityConfig.javal
代码:

http.formLogin()
  .usernameParameter("username")
  .passwordParameter("password")
  .loginPage("/toLogin")
  .loginProcessingUrl("/login"); // 登陆表单提交请求
  • 1
  • 2
  • 3
  • 4
  • 5
5、在登录页增加记住我的多选框

路径:src/main/resources/templates/views/login.html
代码:

 <div class="field">
      <input type="checkbox" name="remember"> 记住我
 </div>
  • 1
  • 2
  • 3
6、后端验证处理!
//定制记住我的参数!
http.rememberMe().rememberMeParameter("remember");
  • 1
  • 2

十三、Shiro

1、Shiro简介

1.1 什么是Shiro?

  • Apache Shiro是一个Java 的安全(权限)框架。
  • Shiro可以非常容易的开发出足够好的应用,其不仅可以用在JavaSE环境,也可以用在JavaEE环境。
  • Shiro可以完成,认证,授权,加密,会话管理,Web集成,缓存等.
    下载地址: http://shiro.apache.org/

1.2 有哪些功能

在这里插入图片描述
在这里插入图片描述

1.3 外部结构

在这里插入图片描述
在这里插入图片描述

1.4 内部结构

在这里插入图片描述
在这里插入图片描述

1.5 核心组件

在这里插入图片描述
在这里插入图片描述

2、快速开始

github地址:https://github.com/apache/shiro
十分钟入门地址:https://shiro.apache.org/10-minute-tutorial.html
mvn仓库:https://mvnrepository.com/

1. 搭建环境

1. 新建项目

在这里插入图片描述
选择依赖
在这里插入图片描述

2. 添加依赖shiro-spring
  1. 地址:https://mvnrepository.com/search?q=shiro-spring 点击第一个进去
    在这里插入图片描述
  2. 点击第一个版本进去
    在这里插入图片描述
  3. 版本代码如下:
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring -->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.8.0</version>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  1. 导入到pom.xml依赖,pom.xml如下:
 <dependencies>
          <!--shiro-spring-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.8.0</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  1. 运行命令

Terminal: mvn clean install
在这里插入图片描述
运行结果
在这里插入图片描述

2. 自定义shiro 过滤器

1. 创建表
/*
 Navicat Premium Data Transfer

 Source Server         : localhost
 Source Server Type    : MySQL
 Source Server Version : 50726
 Source Host           : localhost:3306
 Source Schema         : mybatis

 Target Server Type    : MySQL
 Target Server Version : 50726
 File Encoding         : 65001

 Date: 10/02/2022 10:06:11
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for account
-- ----------------------------
DROP TABLE IF EXISTS `account`;
CREATE TABLE `account`  (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `username` varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL COMMENT '用户名',
  `password` varchar(100) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL COMMENT '密码',
  `perms` varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT '权限',
  `role` varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT '角色',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = MyISAM AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_unicode_ci COMMENT = '账户表' ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of account
-- ----------------------------
INSERT INTO `account` VALUES (1, 'zs', '123123', NULL, NULL);
INSERT INTO `account` VALUES (2, 'ls', '123123', 'manage', NULL);
INSERT INTO `account` VALUES (3, 'www', '123123', 'manage', 'administerator');

SET FOREIGN_KEY_CHECKS = 1;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
2. 添加依赖

注意:
官方依赖:spring-boot-starter + 名字
第三方依赖:名字 + boot-starter

pom.xml


        <!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--mybatis-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.1</version>
        </dependency>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
3. 添加实体类

路径:src/main/java/com/xxx/entity/Account.java
代码:

package com.xxx.entity;

import lombok.Data;

/**
 * entity实体类
 */
@Data
public class Account {
    private Integer id;
    private String username;
    private String password;
    private String perms;
    private String role;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
4. 添加Mapper接口类

路径:src/main/java/com/xxx/mapper/AccountMapper.java
代码:

package com.xxx.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xxx.entity.Account;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface AccountMapper extends BaseMapper<Account> {


}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
5. 配置数据库链接

路径:src/main/resources/application.yaml
代码:

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/mybatis
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
6. 测试

路径:src/test/java/com/xxx/Springboot08ShiroApplicationTests.java
代码:

package com.xxx;

import com.xxx.mapper.AccountMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class Springboot08ShiroApplicationTests {

    @Autowired
    private AccountMapper mapper;
    @Test
    void contextLoads() {
        mapper.selectList(null).forEach(System.out::println);
    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

运行:
在这里插入图片描述

7. service接口类和实现类

新建service接口类:src/main/java/com/xxx/service/AccountService.java
代码:

package com.xxx.service;

import com.xxx.entity.Account;

public interface AccountService {

    public Account finByUsername(String name);
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

新建service实现类:src/main/java/com/xxx/service/impl/AccountServiceImpl.java
代码:

package com.xxx.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.xxx.entity.Account;
import com.xxx.mapper.AccountMapper;
import com.xxx.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class AccountServiceImpl implements AccountService {

    @Autowired
    private AccountMapper accountMapper;

    @Override
    public Account finByUsername(String username) {
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("username", username);
        return accountMapper.selectOne(wrapper);
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

测试类:src/test/java/com/xxx/service/AccountServiceTest.java
代码:

package com.xxx.service;

import com.xxx.entity.Account;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest
class AccountServiceTest {
    @Autowired
    private AccountService accountService;
    @Test
    void  Test(){
        Account zs = accountService.finByUsername("zs");
        System.out.println(zs);
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

运行结果:
在这里插入图片描述

8. realm

路径:src/main/java/com/xxx/config/ShiroConfig.java
代码:

package com.xxx.config;

import com.xxx.realm.AccountRealm;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ShiroConfig {


    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        factoryBean.setSecurityManager(securityManager);
        return factoryBean;
    }

    @Bean
    public DefaultWebSecurityManager securityManager(@Qualifier("accountRealm") AccountRealm accountRealm) {
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        manager.setRealm(accountRealm);
        return manager;
    }

    @Bean
    public AccountRealm accountRealm() {
        return new AccountRealm();
    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

3. realm编写认证和授权规则

1. 需求

在这里插入图片描述
在这里插入图片描述

2. 编写规则

路径:src/main/java/com/xxx/config/ShiroConfig.java
代码:

package com.xxx.config;

import com.xxx.realm.AccountRealm;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Hashtable;
import java.util.Map;

@Configuration
public class ShiroConfig {


    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        factoryBean.setSecurityManager(securityManager);
        //权限设置 认证和授权
        Map<String, String> map = new Hashtable<>();
        map.put("/main","authc");//访问main页面,必须是登录状态
        map.put("/manage","perms[manage]");//访问manage页面,必须有manage权限
        map.put("/administrator","roles[administrator]");//访问administrator页面,必须有administrator角色
        factoryBean.setFilterChainDefinitionMap(map);
        return factoryBean;
    }

    @Bean
    public DefaultWebSecurityManager securityManager(@Qualifier("accountRealm") AccountRealm accountRealm) {
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        manager.setRealm(accountRealm);
        return manager;
    }

    @Bean
    public AccountRealm accountRealm() {
        return new AccountRealm();
    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
3. 配置thymeleaf

路径:src/main/resources/application.yaml
代码:

spring:
  # 数据库配置
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/mybatis
  #thymeleaf配置
  thymeleaf:
    prefix: classpath:/templates/
    suffix: .html
#mybatis-plus 配置    
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
4. 控制层创建

路径:src/main/java/com/xxx/controller/AccountController.java
代码

package com.xxx.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@Controller
public class AccountController {
    @GetMapping("/{url}")
    public String redirect(@PathVariable("url") String url) {
        return url;
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
5. 页面创建
1. main 页面

路径:src/main/resources/templates/main.html
代码

<!DOCTYPE html>
<html lang="en">
<head>
    <link rel="shortcut icon" href="../resources/favicon.ico" th:href="@{/static/favicon.ico}"/>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>main 首页</h1>

</body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
2. manage 页面

路径:src/main/resources/templates/manage.html
代码

<!DOCTYPE html>
<html lang="en">
<head>
    <link rel="shortcut icon" href="../resources/favicon.ico" th:href="@{/static/favicon.ico}"/>
    <meta charset="UTF-8">
    <title>manage</title>
</head>
<body>
<h1>manage </h1>
</body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
3. administrator页面

路径:src/main/resources/templates/administrator.html
代码

<!DOCTYPE html>
<html lang="en">
<head>
    <link rel="shortcut icon" href="../resources/favicon.ico" th:href="@{/static/favicon.ico}"/>
    <meta charset="UTF-8">
    <title>administrator</title>
</head>
<body>
<h1>administrator </h1>
</body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
4.配置成功测试

访问:http://localhost:8080/main 报错,跳转到http://localhost:8080/login.jsp
在这里插入图片描述

5. 取消配置测试

路径:src/main/java/com/xxx/config/ShiroConfig.java
@Configuration 注释掉配置就不会被加载
代码:

package com.xxx.config;

import com.xxx.realm.AccountRealm;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Hashtable;
import java.util.Map;

//@Configuration
public class ShiroConfig {


    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        factoryBean.setSecurityManager(securityManager);
        //权限设置 认证和授权
        Map<String, String> map = new Hashtable<>();
        map.put("/main","authc");//访问main页面,必须是登录状态
        map.put("/manage","perms[manage]");//访问manage页面,必须有manage权限
        map.put("/administrator","roles[administrator]");//访问administrator页面,必须有administrator角色
        factoryBean.setFilterChainDefinitionMap(map);
        return factoryBean;
    }

    @Bean
    public DefaultWebSecurityManager securityManager(@Qualifier("accountRealm") AccountRealm accountRealm) {
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        manager.setRealm(accountRealm);
        return manager;
    }

    @Bean
    public AccountRealm accountRealm() {
        return new AccountRealm();
    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

测试地址:http://localhost:8080/main
在这里插入图片描述

6. 配置index页面

创建地址:src/main/resources/templates/index.html
代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <link rel="shortcut icon" href="../resources/favicon.ico" th:href="@{/static/favicon.ico}"/>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>index</h1>
<a href="/main">main</a>  |
<a href="/manage">manage</a>  |
<a href="/administrator">administrator</a>

</body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

访问:http://localhost:8080/
在这里插入图片描述
点击main
在这里插入图片描述

7. 配置登录页

修改跳转页为登录页
路径:src/main/java/com/xxx/config/ShiroConfig.java
代码:

package com.xxx.config;

import com.xxx.realm.AccountRealm;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Hashtable;
import java.util.Map;

@Configuration
public class ShiroConfig {


    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        factoryBean.setSecurityManager(securityManager);
        //权限设置 认证和授权
        Map<String, String> map = new Hashtable<>();
        map.put("/main", "authc");//访问main页面,必须是登录状态
        map.put("/manage", "perms[manage]");//访问manage页面,必须有manage权限
        map.put("/administrator", "roles[administrator]");//访问administrator页面,必须有administrator角色
        factoryBean.setFilterChainDefinitionMap(map);
        //设置登录页面
        factoryBean.setLoginUrl("/login");
        return factoryBean;
    }

    @Bean
    public DefaultWebSecurityManager securityManager(@Qualifier("accountRealm") AccountRealm accountRealm) {
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        manager.setRealm(accountRealm);
        return manager;
    }

    @Bean
    public AccountRealm accountRealm() {
        return new AccountRealm();
    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

创建登录页面:src/main/resources/templates/login.html
代码:

<!DOCTYPE html>
<html lang="en"
     xmlns:th="http://www.thymeleaf.org">
<head>
    <link rel="shortcut icon" href="../resources/favicon.ico" th:href="@{/static/favicon.ico}"/>
    <meta charset="UTF-8">
    <title>login</title>
</head>
<body>
<form action="/loginSubmit" method="post">
    <table>
        <span th:text="${msg}"></span>
        <tr>
            <td>用户名:</td>
            <td>
                <input type="text" name="username">
            </td>
        </tr>
        <tr>
            <td>密码:</td>
            <td>
                <input type="text" name="password">
            </td>
        </tr>
        <tr>
            <td>
                <input type="submit" value="登录">
            </td>
        </tr>
    </table>

</form>
</body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

访问:http://localhost:8080/
在这里插入图片描述
点击main跳转到http://localhost:8080/login 页面
在这里插入图片描述

4. Shiro整合thymeleaf

1. 提交方法

路径:src/main/java/com/xxx/controller/AccountController.java
代码 :

package com.xxx.controller;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class AccountController {
    //页面跳转
    @GetMapping("/{url}")
    public String redirect(@PathVariable("url") String url) {
        return url;
    }
    //未授权跳转页面
    @GetMapping("/unauth")
    @ResponseBody
    public String unauth(){
        return  "未授权,无法访问";
    }

    //登录提交页面
    @PostMapping("/loginSubmit")
    //try catch 快捷键 “ctrl + alt + t”
    public String login(String username, String password, Model model) {
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        try {
            subject.login(token);
            return "index";
        } catch (UnknownAccountException e) {
            e.printStackTrace();
            model.addAttribute("msg", "用户名错误");
            return "login";
        } catch (IncorrectCredentialsException e) {
            e.printStackTrace();
            model.addAttribute("msg", "密码错误");
            return "login";
        }
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
2. 认证授权

路径:src/main/java/com/xxx/realm/AccountRealm.java
代码 :

package com.xxx.realm;

import com.xxx.entity.Account;
import com.xxx.service.AccountService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.HashSet;
import java.util.Set;

public class AccountRealm extends AuthorizingRealm {
    @Autowired
    private AccountService accountService;

    @Override//实现方法 im 授权判断
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //当前登录的用户信息
        Subject subject = SecurityUtils.getSubject();
        Account account = (Account) subject.getPrincipal();
        //设置角色
        Set<String> roles = new HashSet<>();
        roles.add(account.getRole());
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles);
        //设置权限
        info.addStringPermission(account.getPerms());
        return info;
    }

    @Override//实现方法 im  认证 登录
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        Account account = accountService.finByUsername(token.getUsername());
        if (account != null) {
            //验证密码
            return new SimpleAuthenticationInfo(account, account.getPassword(), getName());
        }
        return null;
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
3. 设置未授权页面

路径:src/main/java/com/xxx/config/ShiroConfig.java
代码:

package com.xxx.config;

import com.xxx.realm.AccountRealm;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Hashtable;
import java.util.Map;

@Configuration
public class ShiroConfig {


    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        factoryBean.setSecurityManager(securityManager);
        //权限设置 认证和授权
        Map<String, String> map = new Hashtable<>();
        map.put("/main", "authc");//访问main页面,必须是登录状态
        map.put("/manage", "perms[manage]");//访问manage页面,必须有manage权限
        map.put("/administrator", "roles[administrator]");//访问administrator页面,必须有administrator角色
        factoryBean.setFilterChainDefinitionMap(map);
        //设置登录页面
        factoryBean.setLoginUrl("/login");
        //设置未授权页面
        factoryBean.setUnauthorizedUrl("/unauth");
        return factoryBean;
    }

    @Bean
    public DefaultWebSecurityManager securityManager(@Qualifier("accountRealm") AccountRealm accountRealm) {
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        manager.setRealm(accountRealm);
        return manager;
    }

    @Bean
    public AccountRealm accountRealm() {
        return new AccountRealm();
    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
4. 登录显示当前用户名
1. 登录页面修改

路径:src/main/resources/templates/index.html
地址:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <link rel="shortcut icon" href="../resources/favicon.ico" th:href="@{/static/favicon.ico}"/>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>index</h1>
<div th:if="${session.account != null}">
    <span th:text="${session.account.username}+'欢迎回来'"></span>
</div>


<a href="/main">main</a> |
<a href="/manage">manage</a> |
<a href="/administrator">administrator</a>

</body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
2. 修改登录方法

路径:src/main/java/com/xxx/controller/AccountController.java
代码:

package com.xxx.controller;

import com.xxx.entity.Account;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class AccountController {
    //页面跳转
    @GetMapping("/{url}")
    public String redirect(@PathVariable("url") String url) {
        return url;
    }

    //未授权跳转页面
    @GetMapping("/unauth")
    @ResponseBody
    public String unauth() {
        return "未授权,无法访问";
    }

    //登录提交页面
    @PostMapping("/loginSubmit")
    //try catch 快捷键 “ctrl + alt + t”
    public String login(String username, String password, Model model) {
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        try {
             //获取登录成功后的信息
            subject.login(token);
            Account account = (Account) subject.getPrincipal();
            subject.getSession().setAttribute("account", account);
            return "index";
        } catch (UnknownAccountException e) {
            e.printStackTrace();
            model.addAttribute("msg", "用户名错误");
            return "login";
        } catch (IncorrectCredentialsException e) {
            e.printStackTrace();
            model.addAttribute("msg", "密码错误");
            return "login";
        }
    }

   
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
5. 退出
1. 登录页面修改

路径:src/main/resources/templates/index.html
代码

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <link rel="shortcut icon" href="../resources/favicon.ico" th:href="@{/static/favicon.ico}"/>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>index</h1>
<div th:if="${session.account != null}">
    <span th:text="${session.account.username}+'欢迎回来'"></span>
    <a href="/logout">退出</a>
</div>


<a href="/main">main</a> |
<a href="/manage">manage</a> |
<a href="/administrator">administrator</a>

</body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
2. 添加退出方法

路径:src/main/java/com/xxx/controller/AccountController.java
代码:

package com.xxx.controller;

import com.xxx.entity.Account;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class AccountController {
    //页面跳转
    @GetMapping("/{url}")
    public String redirect(@PathVariable("url") String url) {
        return url;
    }

    //未授权跳转页面
    @GetMapping("/unauth")
    @ResponseBody
    public String unauth() {
        return "未授权,无法访问";
    }

    //登录提交页面
    @PostMapping("/loginSubmit")
    //try catch 快捷键 “ctrl + alt + t”
    public String login(String username, String password, Model model) {
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        try {
            //获取登录成功后的信息
            subject.login(token);
            Account account = (Account) subject.getPrincipal();
            subject.getSession().setAttribute("account", account);
            return "index";
        } catch (UnknownAccountException e) {
            e.printStackTrace();
            model.addAttribute("msg", "用户名错误");
            return "login";
        } catch (IncorrectCredentialsException e) {
            e.printStackTrace();
            model.addAttribute("msg", "密码错误");
            return "login";
        }
    }

//退出登录
    @GetMapping("/logout")
    public String logout() {
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        return "login";
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
6. 根据登录不同的用户显示不同的权限
1. 引入依赖

pom.xml

 <dependency>
    <groupId>com.github.theborakompanioni</groupId>
    <artifactId>thymeleaf-extras-shiro</artifactId>
    <version>2.0.0</version>
 </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
2. 配置类添加ShiroDialect

路径:src/main/java/com/xxx/config/ShiroConfig.java
代码:

package com.xxx.config;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.xxx.realm.AccountRealm;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Hashtable;
import java.util.Map;

@Configuration
public class ShiroConfig {


    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        factoryBean.setSecurityManager(securityManager);
        //权限设置 认证和授权
        Map<String, String> map = new Hashtable<>();
        map.put("/main", "authc");//访问main页面,必须是登录状态
        map.put("/manage", "perms[manage]");//访问manage页面,必须有manage权限
        map.put("/administrator", "roles[administrator]");//访问administrator页面,必须有administrator角色
        factoryBean.setFilterChainDefinitionMap(map);
        //设置登录页面
        factoryBean.setLoginUrl("/login");
        //设置未授权页面
        factoryBean.setUnauthorizedUrl("/unauth");
        return factoryBean;
    }
    //配置类添加DefaultWebSecurityManager
    @Bean
    public DefaultWebSecurityManager securityManager(@Qualifier("accountRealm") AccountRealm accountRealm) {
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        manager.setRealm(accountRealm);
        return manager;
    }
    //配置类添加AccountRealm
    @Bean
    public AccountRealm accountRealm() {
        return new AccountRealm();
    }

    //配置类添加ShiroDialect
    @Bean
    public ShiroDialect shiroDialect() {
        return new ShiroDialect();

    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
3. index页面

路径:src/main/resources/templates/index.html
代码

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
      xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro">
<head>
    <link rel="shortcut icon" href="../resources/favicon.ico" th:href="@{/static/favicon.ico}"/>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>index</h1>
<div th:if="${session.account != null}">
    <span th:text="${session.account.username}+'欢迎回来'"></span>
    <a href="/logout">退出</a>
</div>


<a href="/main">main</a> |
<!--判断权限-->
<div shiro:hasPermission="manage"><a href="/manage">manage</a> |</div>
<!--判断角色-->
<div shiro:hasRole="administrator"><a href="/administrator">administrator</a></div>


</body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

十四、鸡汤分析开源项目

1. 路径

git 路径: https://github.com/WinterChenS/my-site?tdsourcetag=s_pcqq_aiomsg
前台地址:http://winterchen.com:8089/
后台地址:http://winterchen.com:8089/admin/login
标准的springboot项目:
在这里插入图片描述

2.搭建项目

1. 解压项目

下载解压项目
在这里插入图片描述

2. ide打开项目

1. file->open

在这里插入图片描述

2. 选择打开的项目点击ok

在这里插入图片描述

3. 等待加载

在这里插入图片描述

3. 分析项目

1. 多环境配置

在这里插入图片描述

2. 创建数据库
1. 创建lu_tale

在这里插入图片描述

2. 新建表
/*
 Navicat Premium Data Transfer

 Source Server         : mycould
 Source Server Type    : MariaDB
 Source Server Version : 50556
 Source Host           : 118.25.36.41
 Source Database       : lu_tale

 Target Server Type    : MariaDB
 Target Server Version : 50556
 File Encoding         : utf-8

 Date: 05/03/2018 17:01:52 PM
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
--  Table structure for `t_attach`
-- ----------------------------
DROP TABLE IF EXISTS `t_attach`;
CREATE TABLE `t_attach` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `fname` varchar(100) NOT NULL DEFAULT '',
  `ftype` varchar(50) DEFAULT '',
  `fkey` text NOT NULL,
  `authorId` int(10) DEFAULT NULL,
  `created` int(10) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;



-- ----------------------------
--  Table structure for `t_comments`
-- ----------------------------
DROP TABLE IF EXISTS `t_comments`;
CREATE TABLE `t_comments` (
  `coid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `cid` int(10) unsigned DEFAULT '0',
  `created` int(10) unsigned DEFAULT '0',
  `author` varchar(200) DEFAULT NULL,
  `authorId` int(10) unsigned DEFAULT '0',
  `ownerId` int(10) unsigned DEFAULT '0',
  `mail` varchar(200) DEFAULT NULL,
  `url` varchar(200) DEFAULT NULL,
  `ip` varchar(64) DEFAULT NULL,
  `agent` varchar(200) DEFAULT NULL,
  `content` text,
  `type` varchar(16) DEFAULT 'comment',
  `status` varchar(16) DEFAULT 'approved',
  `parent` int(10) unsigned DEFAULT '0',
  PRIMARY KEY (`coid`),
  KEY `cid` (`cid`),
  KEY `created` (`created`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;

-- ----------------------------
--  Table structure for `t_contents`
-- ----------------------------
DROP TABLE IF EXISTS `t_contents`;
CREATE TABLE `t_contents` (
  `cid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `title` varchar(200) DEFAULT NULL,
  `titlePic` varchar(55) DEFAULT NULL,
  `slug` varchar(200) DEFAULT NULL,
  `created` int(10) unsigned DEFAULT '0',
  `modified` int(10) unsigned DEFAULT '0',
  `content` text COMMENT '内容文字',
  `authorId` int(10) unsigned DEFAULT '0',
  `type` varchar(16) DEFAULT 'post',
  `status` varchar(16) DEFAULT 'publish',
  `tags` varchar(200) DEFAULT NULL,
  `categories` varchar(200) DEFAULT NULL,
  `hits` int(10) unsigned DEFAULT '0',
  `commentsNum` int(10) unsigned DEFAULT '0',
  `allowComment` tinyint(1) DEFAULT '1',
  `allowPing` tinyint(1) DEFAULT '1',
  `allowFeed` tinyint(1) DEFAULT '1',
  PRIMARY KEY (`cid`),
  UNIQUE KEY `slug` (`slug`),
  KEY `created` (`created`)
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;

-- ----------------------------
--  Table structure for `t_logs`
-- ----------------------------
DROP TABLE IF EXISTS `t_logs`;
CREATE TABLE `t_logs` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键编号',
  `action` varchar(100) DEFAULT NULL COMMENT '事件',
  `data` varchar(2000) DEFAULT NULL COMMENT '数据',
  `authorId` int(10) DEFAULT NULL COMMENT '作者编号',
  `ip` varchar(20) DEFAULT NULL COMMENT 'ip地址',
  `created` int(10) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=77 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;

-- ----------------------------
--  Table structure for `t_metas`
-- ----------------------------
DROP TABLE IF EXISTS `t_metas`;
CREATE TABLE `t_metas` (
  `mid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(200) DEFAULT NULL,
  `slug` varchar(200) DEFAULT NULL,
  `type` varchar(32) NOT NULL DEFAULT '',
  `contentType` varchar(32) DEFAULT NULL,
  `description` varchar(200) DEFAULT NULL,
  `sort` int(10) unsigned DEFAULT '0',
  `parent` int(10) unsigned DEFAULT '0',
  PRIMARY KEY (`mid`),
  KEY `slug` (`slug`)
) ENGINE=InnoDB AUTO_INCREMENT=41 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;

-- ----------------------------
--  Table structure for `t_options`
-- ----------------------------
DROP TABLE IF EXISTS `t_options`;
CREATE TABLE `t_options` (
  `name` varchar(32) NOT NULL DEFAULT '',
  `value` varchar(1000) DEFAULT '',
  `description` varchar(200) DEFAULT NULL,
  PRIMARY KEY (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;

-- ----------------------------
--  Records of `t_options`
-- ----------------------------
BEGIN;
INSERT INTO `t_options` VALUES ('baidu_site_verification', null, '百度网站验证码'), ('google_site_verification', null, 'google网站验证码'), ('site_description', null, '网站描述'), ('site_keywords', null, null), ('site_record', null, '备案号'), ('site_title', null, '网站标题'), ('social_csdn', null, 'csdn'), ('social_github', null, 'github'), ('social_jianshu', null, '简书地址'), ('social_resume', null, '简历地址'), ('social_twitter', null, 'twitter'), ('social_weibo', null, '微博地址'), ('social_zhihu', null, '知乎地址');
COMMIT;

-- ----------------------------
--  Table structure for `t_relationships`
-- ----------------------------
DROP TABLE IF EXISTS `t_relationships`;
CREATE TABLE `t_relationships` (
  `cid` int(10) unsigned NOT NULL,
  `mid` int(10) unsigned NOT NULL,
  PRIMARY KEY (`cid`,`mid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;

-- ----------------------------
--  Table structure for `t_users`
-- ----------------------------
DROP TABLE IF EXISTS `t_users`;
CREATE TABLE `t_users` (
  `uid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `username` varchar(32) DEFAULT NULL,
  `password` varchar(64) DEFAULT NULL,
  `email` varchar(200) DEFAULT NULL,
  `homeUrl` varchar(200) DEFAULT NULL,
  `screenName` varchar(32) DEFAULT NULL,
  `created` int(10) unsigned DEFAULT '0',
  `activated` int(10) unsigned DEFAULT '0',
  `logged` int(10) unsigned DEFAULT '0',
  `groupName` varchar(16) DEFAULT 'visitor',
  PRIMARY KEY (`uid`),
  UNIQUE KEY `name` (`username`),
  UNIQUE KEY `mail` (`email`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;

-- ----------------------------
--  Records of `t_users` password 123456
-- ----------------------------
BEGIN;
INSERT INTO `t_users` VALUES ('1', 'admin', 'a66abb5684c45962d887564f08346e8d', '1034683568@qq.com', null, 'admin', '1490756162', '0', '0', 'visitor');
COMMIT;

SET FOREIGN_KEY_CHECKS = 1;

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
3. ide 链接

在这里插入图片描述

3. 运行
1. 报错

IDEA Error:(15, 16) java: 程序包sun.misc不存在 或import sun.misc.BASE64Decoder无法找到
在这里插入图片描述
数据库链接失败
查看用户名或者密码是否错误
在这里插入图片描述

2. 运行

路径:http://localhost:8089/
后台路径:http://localhost:8089/admin/
用户名:admin 密码:123456
在这里插入图片描述
在这里插入图片描述

十五、Swagger

1. Swagger简介

前后端分离

  • 前端 -> 前端控制层、视图层

  • 后端 -> 后端控制层、服务层、数据访问层

  • 前后端通过API进行交互

  • 前后端相对独立且松耦合

产生的问题

  • 前后端集成,前端或者后端无法做到“及时协商,尽早解决”,最终导致问题集中爆发

解决方案

  • 首先定义schema [ 计划的提纲 ],并实时跟踪最新的API,降低集成风险

Swagger

  • 号称世界上最流行的API框架

  • Restful Api 文档在线自动生成器 => API 文档 与API 定义同步更新

  • 直接运行,在线测试API

  • 支持多种语言 (如:Java,PHP等)

  • 官网:https://swagger.io

2. SpringBoot集成Swagger

访问测试 :http://localhost:8080/swagger-ui.html ,可以看到swagger的界面;

在这里插入图片描述
SpringBoot集成Swagger => springfox,两个jar包

使用Swagger

  • 要求:jdk 1.8 + 否则swagger2无法运行

1. 新建SpringBoot-web项目

1. File->New Project

项目名称:springboot-09-swagger
在这里插入图片描述

2. 选择依赖,点击Finish

在这里插入图片描述

3. pom.xml导入依赖
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
<dependency>
   <groupId>io.springfox</groupId>
   <artifactId>springfox-swagger2</artifactId>
   <version>2.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
<dependency>
   <groupId>io.springfox</groupId>
   <artifactId>springfox-swagger-ui</artifactId>
   <version>2.9.2</version>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
4. 新建HelloController类

路径:src/main/java/com/xxx/controller/HelloController.java
代码:

package com.xxx.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class HelloController {

    @ResponseBody
    @GetMapping("HelloTest")
    public String HelloTest(){
        return "hello test";
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
5. 测试运行

路径:http://localhost:8080/HelloTest
在这里插入图片描述

2. 编写配置类-SwaggerConfig

1. 创建配置类

路径:src/main/java/com/xxx/config/SwaggerConfig.java
代码:

package com.xxx.config;


import org.springframework.context.annotation.Configuration;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
public class SwaggerConfig {

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

3. 配置文件

解决高版本SpringBoot整合swagger时启动报错:Failed to start bean ‘documentationPluginsBootstrapper’; nested exception is java.lang.NullPointerException问题

1. 方法一:配置文件

路径:src/main/resources/application.properties
代码:

spring.mvc.pathmatch.matching-strategy=ant_path_matcher


  • 1
  • 2
  • 3
2. 方法二:配置 WebMvcConfigurer.java

路径:src/main/java/com/xxx/config/WebMvcConfigurer.java
代码

package com.clesun.brandarchive.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

/**
 * 解决高版本springboot整合swagger启动报错Failed to start bean 'documentationPluginsBootstrapper' 问题
 * @author Administrator
 */
@Configuration
public class WebMvcConfigurer extends WebMvcConfigurationSupport {

    /**
     * 发现如果继承了WebMvcConfigurationSupport,则在yml中配置的相关内容会失效。 需要重新指定静态资源
     * @param registry
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**").addResourceLocations(
                "classpath:/static/");
        registry.addResourceHandler("swagger-ui.html", "doc.html").addResourceLocations(
                "classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations(
                "classpath:/META-INF/resources/webjars/");
        super.addResourceHandlers(registry);
    }

}


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

4. 运行

访问:http://localhost:8080/swagger-ui.html
在这里插入图片描述

3. 配置Swagger

1、配置Docket实例来配置Swaggger

Swagger实例Bean是Docket,所以通过配置Docket实例来配置Swaggger。
路径:src/main/java/com/xxx/config/SwaggerConfig.java
代码:

@Bean //配置docket以配置Swagger具体参数
public Docket docket() {
   return new Docket(DocumentationType.SWAGGER_2);
}
  • 1
  • 2
  • 3
  • 4

2、可以通过apiInfo()属性配置文档信息

路径:src/main/java/com/xxx/config/SwaggerConfig.java
代码:

//配置文档信息
private ApiInfo apiInfo() {
   Contact contact = new Contact("联系人名字", "http://xxx.xxx.com/联系人访问链接", "联系人邮箱");
   return new ApiInfo(
           "Swagger学习", // 标题
           "学习演示如何配置Swagger", // 描述
           "v1.0", // 版本
           "http://terms.service.url/组织链接", // 组织链接
           contact, // 联系人信息
           "Apach 2.0 许可", // 许可
           "许可链接", // 许可连接
           new ArrayList<>()// 扩展
  );
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

3、Docket 实例关联上 apiInfo()

路径:src/main/java/com/xxx/config/SwaggerConfig.java
代码:

@Bean
public Docket docket() {
   return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo());
}
  • 1
  • 2
  • 3
  • 4

4. 全部SwaggerConfig配置代码

路径:src/main/java/com/xxx/config/SwaggerConfig.java
代码:

package com.xxx.config;


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.util.ArrayList;

@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @Bean //配置docket以配置Swagger具体参数
    public Docket docket() {
        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo());
    }

    //配置信息
    private ApiInfo apiInfo() {
        Contact contact = new Contact("联系人名字", "https://xxx.xxx.com/联系人访问链接", "联系人邮箱");
        return new ApiInfo(
                "Swagger学习",//标题
                "学习演示如何配置Swagger",//描述
                "v1.0",//版本
                "http://terms.service.url/组织链接",//组织链接
                contact,//联系人信息
                "Apach  2.0 许可",//许可
                "许可链接",//许可链接
                new ArrayList<>()//扩展
        );

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

5. 测试

访问: http://localhost:8080/swagger-ui.html
在这里插入图片描述

4. 配置扫描接口

1、配置包路径配置扫描

构建Docket时通过select()方法配置怎么扫描接口。
路径:src/main/java/com/xxx/config/SwaggerConfig.java
代码:

@Bean
public Docket docket() {
   return new Docket(DocumentationType.SWAGGER_2)
      .apiInfo(apiInfo())
      .select()// 通过.select()方法,去配置扫描接口,RequestHandlerSelectors配置如何扫描接口
      .apis(RequestHandlerSelectors.basePackage("com.kuang.swagger.controller"))
      .build();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

2、重启项目测试

由于我们配置根据包的路径扫描接口,所以我们只能看到一个类
访问: http://localhost:8080/swagger-ui.html
在这里插入图片描述

3、配置其他方式扫描接口

除了通过包路径配置扫描接口外,还可以通过配置其他方式扫描接口,这里注释一下所有的配置方式:

any() // 扫描所有,项目中的所有接口都会被扫描到
none() // 不扫描接口
// 通过方法上的注解扫描,如withMethodAnnotation(GetMapping.class)只扫描get请求
withMethodAnnotation(final Class<? extends Annotation> annotation)
// 通过类上的注解扫描,如.withClassAnnotation(Controller.class)只扫描有controller注解的类中的接口
withClassAnnotation(final Class<? extends Annotation> annotation)
basePackage(final String basePackage) // 根据包路径扫描接口
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

4、配置接口扫描过滤

1. 配置

路径:src/main/java/com/xxx/config/SwaggerConfig.java
代码:

@Bean
public Docket docket() {
   return new Docket(DocumentationType.SWAGGER_2)
      .apiInfo(apiInfo())
      .select()// 通过.select()方法,去配置扫描接口,RequestHandlerSelectors配置如何扫描接口
      .apis(RequestHandlerSelectors.basePackage("com.kuang.swagger.controller"))
       // 配置如何通过path过滤,即这里只扫描请求以/xxx开头的接口
      .paths(PathSelectors.ant("/xxx/**"))
      .build();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
2. 这里的可选值还有
any() // 任何请求都扫描
none() // 任何请求都不扫描
regex(final String pathRegex) // 通过正则表达式控制
ant(final String antPattern) // 通过ant()控制
  • 1
  • 2
  • 3
  • 4
3. 运行测试
1. 以hello开头的

在这里插入图片描述
路径:http://127.0.0.1:8081/swagger-ui.html
运行后不显示
在这里插入图片描述

2 . 以xxx开头的

在这里插入图片描述
路径:http://127.0.0.1:8081/swagger-ui.html
测试结果
在这里插入图片描述

5、全部SwaggerConfig配置代码

路径:src/main/java/com/xxx/config/SwaggerConfig.java
代码:

package com.xxx.config;


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.util.ArrayList;

@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @Bean //配置docket以配置Swagger具体参数
    public Docket docket() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()// 通过.select()方法,去配置扫描接口,RequestHandlerSelectors配置如何扫描接口
                .apis(RequestHandlerSelectors.basePackage("com.xxx.controller"))
                // 配置如何通过path过滤,即这里只扫描请求以/xxx开头的接口
                .paths(PathSelectors.ant("/xxx/**"))
                .build();
    }

    //配置信息
    private ApiInfo apiInfo() {
        Contact contact = new Contact("联系人名字", "https://xxx.xxx.com/联系人访问链接", "联系人邮箱");
        return new ApiInfo(
                "Swagger学习",//标题
                "学习演示如何配置Swagger",//描述
                "v1.0",//版本
                "http://terms.service.url/组织链接",//组织链接
                contact,//联系人信息
                "Apach  2.0 许可",//许可
                "许可链接",//许可链接
                new ArrayList<>()//扩展
        );

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

5. 配置Swagger开关

1、配置是否启用swagger

通过enable()方法配置是否启用swagger,如果是false,swagger将不能在浏览器中访问了

路径:src/main/java/com/xxx/config/SwaggerConfig.java
代码:

@Bean
public Docket docket() {
   return new Docket(DocumentationType.SWAGGER_2)
      .apiInfo(apiInfo())
      .enable(false) //配置是否启用Swagger,如果是false,在浏览器将无法访问
      .select()// 通过.select()方法,去配置扫描接口,RequestHandlerSelectors配置如何扫描接口
      .apis(RequestHandlerSelectors.basePackage("com.kuang.swagger.controller"))
       // 配置如何通过path过滤,即这里只扫描请求以/xxx开头的接口
      .paths(PathSelectors.ant("/xxx/**"))
      .build();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

2、动态配置当配置是否启用swagger

如何动态配置当项目处于test、dev环境时显示swagger,处于prod时不显示?

1. 新建开发环境dev

路径:src/main/resources/application-dev.properties

# 开发环境 生产环境
server.port=8081
  • 1
  • 2
2. 新建正式环境pro

路径:src/main/resources/application-pro.properties
代码:

# 正式环境
server.port=8082
  • 1
  • 2
3. 配置激活环境

路径:src/main/resources/application.properties
代码:

spring.mvc.pathmatch.matching-strategy=ant_path_matcher
# 切换环境
 spring.profiles.active=dev


  • 1
  • 2
  • 3
  • 4
  • 5
4. 修改代码

如果是dev 或者test环境显示
路径:src/main/java/com/xxx/config/SwaggerConfig.java
代码:

@Bean
public Docket docket(Environment environment) {
   // 设置要显示swagger的环境
   Profiles of = Profiles.of("dev", "test");
   // 判断当前是否处于该环境
   // 通过 enable() 接收此参数判断是否要显示
   boolean flag = environment.acceptsProfiles(of);
   
   return new Docket(DocumentationType.SWAGGER_2)
      .apiInfo(apiInfo())
      .enable(flag) //配置是否启用Swagger,如果是false,在浏览器将无法访问
      .select()// 通过.select()方法,去配置扫描接口,RequestHandlerSelectors配置如何扫描接口
      .apis(RequestHandlerSelectors.basePackage("com.xxx.controller"))
       // 配置如何通过path过滤,即这里只扫描请求以/xxx开头的接口
      .paths(PathSelectors.ant("/xxx/**"))
      .build();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

完整代码如下
路径:src/main/java/com/xxx/config/SwaggerConfig.java
代码:

package com.xxx.config;


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.env.Profiles;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.util.ArrayList;

@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @Bean //配置docket以配置Swagger具体参数
    public Docket docket(Environment environment) {
        //设置要显示的swagger环境
        Profiles profiles = Profiles.of("dev", "test");
        //通过environment.acceptsProfiles判断是否处在自己设定的环境中
        boolean flag = environment.acceptsProfiles(profiles);

        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .enable(flag)//配置是否启用Swagger,如果是false,在浏览器将无法访问
                .select()// 通过.select()方法,去配置扫描接口,RequestHandlerSelectors配置如何扫描接口
                .apis(RequestHandlerSelectors.basePackage("com.xxx.controller"))
                // 配置如何通过path过滤,即这里只扫描请求以/xxx开头的接口
                .paths(PathSelectors.ant("/xxx/**"))
                .build();
    }

    //配置信息
    private ApiInfo apiInfo() {
        Contact contact = new Contact("联系人名字", "https://xxx.xxx.com/联系人访问链接", "联系人邮箱");
        return new ApiInfo(
                "Swagger学习",//标题
                "学习演示如何配置Swagger",//描述
                "v1.0",//版本
                "http://terms.service.url/组织链接",//组织链接
                contact,//联系人信息
                "Apach  2.0 许可",//许可
                "许可链接",//许可链接
                new ArrayList<>()//扩展
        );

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
5. 测试
1. 选择默认环境

路径:src/main/resources/application.properties
代码:

spring.mvc.pathmatch.matching-strategy=ant_path_matcher
# 切换环境
# spring.profiles.active=dev
  • 1
  • 2
  • 3

访问:http://localhost:8080/swagger-ui.html#/
在这里插入图片描述

2. 选择dev环境

路径:src/main/resources/application.properties
代码:

spring.mvc.pathmatch.matching-strategy=ant_path_matcher
# 切换环境
 spring.profiles.active=dev
  • 1
  • 2
  • 3

访问:http://localhost:8081/swagger-ui.html
在这里插入图片描述

6. 配置API分组

如果没有配置分组,默认是default。
在这里插入图片描述

1. 通过groupName()方法即可配置分组

路径:src/main/java/com/xxx/config/SwaggerConfig.java
代码:

@Bean
public Docket docket(Environment environment) {
   return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
      .groupName("fj") // 配置分组
       // 省略配置....
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

访问:http://localhost:8081/swagger-ui.html
在这里插入图片描述

2. 如何配置多个分组

配置多个分组只需要配置多个docket即可:

  @Bean
    public Docket docket1() {
        return new Docket(DocumentationType.SWAGGER_2).groupName("a");
    }
    @Bean
    public Docket docket2() {
        return new Docket(DocumentationType.SWAGGER_2).groupName("b");
    }
    @Bean
    public Docket docket3() {
        return new Docket(DocumentationType.SWAGGER_2).groupName("c");
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

全部代码
路径:src/main/java/com/xxx/config/SwaggerConfig.java
代码:

package com.xxx.config;


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.env.Profiles;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.util.ArrayList;

@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @Bean
    public Docket docket1() {
        return new Docket(DocumentationType.SWAGGER_2).groupName("a");
    }
    @Bean
    public Docket docket2() {
        return new Docket(DocumentationType.SWAGGER_2).groupName("b");
    }
    @Bean
    public Docket docket3() {
        return new Docket(DocumentationType.SWAGGER_2).groupName("c");
    }
    @Bean //配置docket以配置Swagger具体参数
    public Docket docket(Environment environment) {
        //设置要显示的swagger环境
        Profiles profiles = Profiles.of("dev", "test");
        //通过environment.acceptsProfiles判断是否处在自己设定的环境中
        boolean flag = environment.acceptsProfiles(profiles);

        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("fj")
                .apiInfo(apiInfo())
                .enable(flag)//配置是否启用Swagger,如果是false,在浏览器将无法访问
                .select()// 通过.select()方法,去配置扫描接口,RequestHandlerSelectors配置如何扫描接口
                .apis(RequestHandlerSelectors.basePackage("com.xxx.controller"))
                // 配置如何通过path过滤,即这里只扫描请求以/xxx开头的接口
                .paths(PathSelectors.ant("/xxx/**"))
                .build();
    }

    //配置信息
    private ApiInfo apiInfo() {
        Contact contact = new Contact("联系人名字", "https://xxx.xxx.com/联系人访问链接", "联系人邮箱");
        return new ApiInfo(
                "Swagger学习",//标题
                "学习演示如何配置Swagger",//描述
                "v1.0",//版本
                "http://terms.service.url/组织链接",//组织链接
                contact,//联系人信息
                "Apach  2.0 许可",//许可
                "许可链接",//许可链接
                new ArrayList<>()//扩展
        );

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67

重启项目查看即可
在这里插入图片描述

7. 实体配置

1、新建一个实体类

路径:src/main/java/com/xxx/pojo/User.java
代码:

package com.xxx.pojo;

public class User {
    public String username;
    public String password;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

2. 实现一个接口返回值是实体类(即使是泛型)的接口

路径:src/main/java/com/xxx/controller/HelloController.java
代码:

package com.xxx.controller;

import com.xxx.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class HelloController {

    @ResponseBody
    @GetMapping("/hello")
    public String HelloTest() {
        return "hello test";
    }

    @GetMapping("/user")
    public User user() {
        return new User();
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

3. 重启查看测试

注意:注释掉路径过滤,否则不显示接口
路径:src/main/java/com/xxx/config/SwaggerConfig.java
代码:

  @Bean //配置docket以配置Swagger具体参数
    public Docket docket(Environment environment) {
          //... 以上配置省略
          // 配置如何通过path过滤,即这里只扫描请求以/xxx开头的接口
          // .paths(PathSelectors.ant("/xxx/**"))
             .build();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

访问:http://127.0.0.1:8081/swagger-ui.html?urls.primaryName=fj#/hello-controller
在这里插入图片描述

4. 添加注释注解

注:并不是因为@ApiModel这个注解让实体显示在这里了,而是只要出现在接口方法的返回值上的实体都会显示在这里,而@ApiModel和@ApiModelProperty这两个注解只是为实体添加注释的。

  • @ApiModel为类添加注释
  • @ApiModelProperty为类属性添加注释

路径:src/main/java/com/xxx/pojo/User.java
代码:

package com.xxx.pojo;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

@ApiModel("用户实体类")
public class User {
    @ApiModelProperty("用户名")
    public String username;
    @ApiModelProperty("密码")
    public String password;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

运行
访问:http://127.0.0.1:8081/swagger-ui.html?urls.primaryName=fj#/
在这里插入图片描述

8. 常用注解

1. 常用注解说明

Swagger的所有注解定义在io.swagger.annotations包下

下面列一些经常用到的,未列举出来的可以另行查阅说明:

Swagger注解简单说明
@Api(tags = “xxx模块说明”)作用在模块类上
@ApiOperation(“xxx接口说明”)作用在接口方法上
@ApiModel(“xxxPOJO说明”)作用在模型类上:如VO、BO
@ApiModelProperty(value = “xxx属性说明”,hidden = true)作用在类方法和属性上,hidden设置为true可以隐藏该属性
@ApiParam(“xxx参数说明”)作用在参数、方法和字段上,类似@ApiModelProperty

2. 实例说明

我们也可以给请求的接口配置一些注释
路径:src/main/java/com/xxx/controller/HelloController.java
代码:

  package com.xxx.controller;

import com.xxx.pojo.User;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

@Controller
public class HelloController {
    /* 方法注解 */
    @ApiOperation(value = "desc of method", notes = "")
    @GetMapping(value = "/hello")
    @ResponseBody
    public Object hello( /* 参数注解 required:必填 */ @ApiParam(value = "desc of param", required = true) @RequestParam String name) {
        return "Hello " + name + "!";
    }

    @ApiOperation("获取用户名")
    @PostMapping("/getUsername")
    @ResponseBody
    public String getUsername(@ApiParam("这个名字会被返回") @RequestParam String username) {
        return "hello" + username;
    }

    @ApiOperation("添加用户")
    @PostMapping("/addUser")// @RequestBody
    @ResponseBody
    public User user(@RequestBody User user) {
        return user;
    }


}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

测试结果
访问:http://127.0.0.1:8081/swagger-ui.html?urls.primaryName=fj
方法上加了注释@ApiOperation
在这里插入图片描述
参数上加了注释@ApiParam
在这里插入图片描述
测试运行接口Try it out
在这里插入图片描述
执行接口
在这里插入图片描述

9. 拓展:其他皮肤

我们可以导入不同的包实现不同的皮肤定义:

1、默认

访问 http://localhost:8080/swagger-ui.html

<dependency>
   <groupId>io.springfox</groupId>
   <artifactId>springfox-swagger-ui</artifactId>
   <version>2.9.2</version>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5

在这里插入图片描述

2、bootstrap-ui

访问 http://localhost:8080/doc.html

<!-- 引入swagger-bootstrap-ui包 /doc.html-->
<dependency>
   <groupId>com.github.xiaoymin</groupId>
   <artifactId>swagger-bootstrap-ui</artifactId>
   <version>1.9.1</version>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在这里插入图片描述

3、Layui-ui

访问 http://localhost:8080/docs.html

<!-- 引入swagger-ui-layer包 /docs.html-->
<dependency>
   <groupId>com.github.caspar-chen</groupId>
   <artifactId>swagger-ui-layer</artifactId>
   <version>1.1.3</version>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在这里插入图片描述

4、mg-ui

访问 http://localhost:8080/document.html

<!-- 引入swagger-ui-layer包 /document.html-->
<dependency>
   <groupId>com.zyplayer</groupId>
   <artifactId>swagger-mg-ui</artifactId>
   <version>1.0.6</version>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在这里插入图片描述

十六、异步、定时、邮件任务

1. 异步任务

1. 新建环境

创建springboot-10-task项目
在这里插入图片描述
选择依赖,finish
在这里插入图片描述

2. 延时测试

1. 创建服务层

路径:src/main/java/com/xxx/service/AsyncService.java
代码:

package com.xxx.service;

import org.springframework.stereotype.Service;

@Service
public class AsyncService {
    //CTRL+ALT+T
    public void hello() {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("数据正在处理。。。。。");
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
2. 控制层

路径:src/main/java/com/xxx/controller/AsyncController.java
代码:

package com.xxx.controller;

import com.xxx.service.AsyncService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

@RestController
public class AsyncController {
    @Resource
    AsyncService asyncService;

    @RequestMapping("/hello")
    public String hello() {
        asyncService.hello();//停止三秒
        return "ok";

    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
3. 测试

访问:http://localhost:8080/hello
控制台打印出数据
在这里插入图片描述
转三秒出现ok
在这里插入图片描述

3. 实现异步

1. service层方法添加异步注解@Async

路径:src/main/java/com/xxx/service/AsyncService.java
代码:

package com.xxx.service;

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

@Service
public class AsyncService {
    //CTRL+ALT+T
    //告诉Spring这是一个异步方法
    @Async
    public void hello() {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("数据正在处理。。。。。");
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
2. 启动类添加注解@EnableAsync

路径:src/main/java/com/xxx/Springboot10TaskApplication.java
代码:

package com.xxx;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;

@EnableAsync//开启异步注解功能
@SpringBootApplication
public class Springboot10TaskApplication {

    public static void main(String[] args) {
        SpringApplication.run(Springboot10TaskApplication.class, args);
    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
3. 测试

访问:http://localhost:8080/hello
瞬间出现ok
在这里插入图片描述
三秒后控制台打印出数据
在这里插入图片描述

2. 邮件任务

邮件发送,在我们的日常开发中,也非常的多,Springboot也帮我们做了支持

  • 邮件发送需要引入spring-boot-start-mail

  • SpringBoot 自动配置MailSenderAutoConfiguration

  • 定义MailProperties内容,配置在application.yml中

  • 自动装配JavaMailSender

  • 测试邮件发送

1. 引入依赖

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-mail</artifactId>
</dependency>
  • 1
  • 2
  • 3
  • 4

点击spring-boot-starter-mail 进去发现有三个依赖
路径:spring-boot-starter-mail-2.6.5.pom
代码:

<dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
      <version>2.6.5</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context-support</artifactId>
      <version>5.3.17</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>com.sun.mail</groupId>
      <artifactId>jakarta.mail</artifactId>
      <version>1.6.7</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
1. 查看自动配置类

路径:查看自动配置类:MailSenderAutoConfiguration
这个类中没有注册bean
在这里插入图片描述
点开MailSenderJndiConfiguration.class这个类中存在bean,JavaMailSenderImpl
在这里插入图片描述
点击private final MailProperties properties;中的MailProperties然后我们去看下配置文件

package org.springframework.boot.autoconfigure.mail;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(
    prefix = "spring.mail"
)
public class MailProperties {
    private static final Charset DEFAULT_CHARSET;
    private String host;
    private Integer port;
    private String username;
    private String password;
    private String protocol = "smtp";
    private Charset defaultEncoding;
    private Map<String, String> properties;
    private String jndiName;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

2. 获取邮箱授权码

在QQ邮箱中的设置->账户->开启pop3和smtp服务
在这里插入图片描述
提示生成授权码,点击蓝色的生成授权码
在这里插入图片描述
弹窗需要发送短信
在这里插入图片描述
发送完成生成授权码
在这里插入图片描述

3. 配置文件

路径:src/main/resources/application.properties
代码:

# 你的qq用户名
spring.mail.username=1251695517@qq.com
# 你的qq授权码
spring.mail.password=htqcvvncsufngbih
spring.mail.host=smtp.qq.com
#开启加密
spring.mail.properties.mail.smtp.ssl.enable=true
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

4. 简单邮件发送

1. 编写代码

路径: com/xxx/Springboot10TaskApplicationTests.java
代码:

package com.xxx;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSenderImpl;

import javax.annotation.Resource;

@SpringBootTest
class Springboot10TaskApplicationTests {
    @Resource
    JavaMailSenderImpl mailSender;

     //邮件设置1:一个简单的邮件
    @Test
    void contextLoads() {
        SimpleMailMessage mailMessage = new SimpleMailMessage();
        mailMessage.setSubject("hello hello 你好啊");
        mailMessage.setText("就是一个测试啊,别多想");
        mailMessage.setTo("1251695517@qq.com");
        mailMessage.setFrom("1251695517@qq.com");
        mailSender.send(mailMessage);

    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
2. 查看邮件

在这里插入图片描述

4. 复杂邮件发送

1. 编写代码

路径: com/xxx/Springboot10TaskApplicationTests.java
代码:

package com.xxx;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;


import javax.annotation.Resource;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.File;

@SpringBootTest
class Springboot10TaskApplicationTests {
    @Resource
    JavaMailSenderImpl mailSender;

    //邮件设置1:一个简单的邮件
    @Test
    void contextLoads() {
        SimpleMailMessage mailMessage = new SimpleMailMessage();
        mailMessage.setSubject("hello hello 你好啊");
        mailMessage.setText("就是一个测试啊,别多想");
        mailMessage.setTo("1251695517@qq.com");
        mailMessage.setFrom("1251695517@qq.com");
        mailSender.send(mailMessage);

    }

    //邮件设置2:一个复杂的邮件
    @Test
    void contextLoads2() throws MessagingException {
        //邮件设置2:一个复杂的邮件
        MimeMessage mimeMessage = mailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
        //正文
        helper.setSubject("复杂邮件测试");
        helper.setText("<p style='color:red'>复杂邮件测试文本</p>",true);
        //附件
        helper.addAttachment("img.jpg",new File("C:\\Users\\f'j\\Pictures\\Saved Pictures\\gaitubao_sanmao_jpg.jpg"));
        helper.addAttachment("img2.jpg",new File("C:\\Users\\f'j\\Pictures\\Saved Pictures\\gaitubao_a_jpg.jpg"));
        //发送
        helper.setTo("1251695517@qq.com");
        helper.setFrom("1251695517@qq.com");
        mailSender.send(mimeMessage);
    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
2. 查看邮件

在这里插入图片描述

3. 定时任务

1. 定时任务讲解

项目开发中经常需要执行一些定时任务,比如需要在每天凌晨的时候,分析一次前一天的日志信息,Spring为我们提供了异步执行任务调度的方式,提供了两个接口

  • TaskExecutor接口 ----> 任务执行者

  • TaskScheduler接口 ----> 任务调度者

两个注解:

  • @EnableScheduling —> 开启定时任务注解功能

  • @Scheduled —> 什么时候执行

2. cron表达式介绍

cron表达式格式:

cron表达式:

字段允许值允许的特殊字符
秒(Seconds)0~59的整数,- * / 四个字符
分(Minutes)0~59的整数, - * / 四个字符
小时(Hours)0~23的整数,- * / 四个字符
日期(DayofMonth)1~31的整数(但是你需要考虑你月的天数),- * ? / L W C 八个字符
月份(Month)1~12的整数或者 JAN-DEC,- * / 四个字符
秒(Seconds)0~59的整数,- * / 四个字符
星期(DayofWeek)1~7的整数或者 SUN-SAT (1=SUN), - * ? / L C # 八个字符
年(可选,留空)(Year)1970~2099, - * / 四个字符

cron表达式特殊字符说明:

特殊字符说明
*表示匹配该域的任意值。假如在Minutes域使用*, 即表示每分钟都会触发事件。
?只能用在DayofMonth和DayofWeek两个域。它也匹配域的任意值,但实际不会。因为DayofMonth和DayofWeek会相互影响。例如想在每月的20日触发调度,不管20日到底是星期几,则只能使用如下写法: 13 13 15 20 * ?, 其中最后一位只能用?,而不能使用*,如果使用*表示不管星期几都会触发,实际上并不是这样。
-表示范围。例如在Minutes域使用5-20,表示从5分到20分钟每分钟触发一次 。
/表示起始时间开始触发,然后每隔固定时间触发一次。例如在Minutes域使用5/20,则意味着5分钟触发一次,而25,45等分别触发一次。
,表示列出枚举值。例如:在Minutes域使用5,20,则意味着在5和20分每分钟触发一次。
L表示最后,只能出现在DayofWeek和DayofMonth域。如果在DayofWeek域使用5L,意味着在最后的一个星期四触发。
W表示有效工作日(周一到周五),只能出现在DayofMonth域,系统将在离指定日期的最近的有效工作日触发事件。例如:在 DayofMonth使用5W,如果5日是星期六,则将在最近的工作日:星期五,即4日触发。如果5日是星期天,则在6日(周一)触发;如果5日在星期一到星期五中的一天,则就在5日触发。另外一点,W的最近寻找不会跨过月份 。
LW这两个字符可以连用,表示在某个月最后一个工作日,即最后一个星期五。
#用于确定每个月第几个星期几,只能出现在DayofMonth域。例如在4#2,表示某月的第二个星期三。
C和calendar联系后计算过的值

cron表达式经典案例:

表达式简介
“30 * * * * ?”每半分钟触发任务
“30 10 * * * ?”每小时的10分30秒触发任务
“30 10 1 * * ?”每天1点10分30秒触发任务
“30 10 1 20 * ?”每月20号1点10分30秒触发任务
“30 10 1 20 10 ? *”每年10月20号1点10分30秒触发任务
“30 10 1 20 10 ? 2011”2011年10月20号1点10分30秒触发任务
“30 10 1 ? 10 * 2011”2011年10月每天1点10分30秒触发任务
“30 10 1 ? 10 SUN 2011”2011年10月每周日1点10分30秒触发任务
“15,30,45 * * * * ?”每15秒,30秒,45秒时触发任务
“15-45 * * * * ?”15到45秒内,每秒都触发任务
“15/5 * * * * ?”每分钟的每15秒开始触发,每隔5秒触发一次
“15-30/5 * * * * ?”每分钟的15秒到30秒之间开始触发,每隔5秒触发一次
“0 0/3 * * * ?”每小时的第0分0秒开始,每三分钟触发一次
“0 15 10 ? * MON-FRI”星期一到星期五的10点15分0秒触发任务
“0 15 10 L * ?”每个月最后一天的10点15分0秒触发任务
“0 15 10 LW * ?”每个月最后一个工作日的10点15分0秒触发任务
“0 15 10 ? * 5L”每个月最后一个星期四的10点15分0秒触发任务
“0 15 10 ? * 5#3”每个月第三周的星期四的10点15分0秒触发任务

其他案例

10/2 * * * * ?   表示每2秒 执行任务
(10 0/2 * * * ?   表示每2分钟 执行任务
(10 0 2 1 * ?   表示在每月的1日的凌晨2点调整任务
(20 15 10 ? * MON-FRI   表示周一到周五每天上午10:15执行作业
(30 15 10 ? 6L 2002-2006   表示2002-2006年的每个月的最后一个星期五上午10:15执行作
(40 0 10,14,16 * * ?   每天上午10点,下午2点,4点
(50 0/30 9-17 * * ?   朝九晚五工作时间内每半小时
(60 0 12 ? * WED   表示每个星期三中午12点
(70 0 12 * * ?   每天中午12点触发
(80 15 10 ? * *   每天上午10:15触发
(90 15 10 * * ?     每天上午10:15触发
(100 15 10 * * ?   每天上午10:15触发
(110 15 10 * * ? 2005   2005年的每天上午10:15触发
(120 * 14 * * ?     在每天下午2点到下午2:59期间的每1分钟触发
(130 0/5 14 * * ?   在每天下午2点到下午2:55期间的每5分钟触发
(140 0/5 14,18 * * ?     在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
(150 0-5 14 * * ?   在每天下午2点到下午2:05期间的每1分钟触发
(160 10,44 14 ? 3 WED   每年三月的星期三的下午2:102:44触发
(170 15 10 ? * MON-FRI   周一至周五的上午10:15触发
(180 15 10 15 * ?   每月15日上午10:15触发
(190 15 10 L * ?   每月最后一日的上午10:15触发
(200 15 10 ? * 6L   每月的最后一个星期五上午10:15触发
(210 15 10 ? * 6L 2002-2005   2002年至2005年的每月的最后一个星期五上午10:15触发
(220 15 10 ? * 6#3   每月的第三个星期五上午10:15触发
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

3. 实现定时任务

1. 编写服务类

路径:src/main/java/com/xxx/service/ScheduledService.java
代码:

package com.xxx.service;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

@Service
public class ScheduledService {
    //在一个特定的时间执行这行代码
    // 秒 分 时 日 月 周几
    // 周0到周7 每到0秒执行
    @Scheduled(cron = "0 * * * * 0-7")
    public void hello() {
        System.out.println("hello,你被执行了");
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
2. 启动类添加定时任务注解

路径:src/main/java/com/xxx/Springboot10TaskApplication.java
代码:

package com.xxx;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;

@EnableAsync//开启异步注解功能
@EnableScheduling //开启定时注解功能
@SpringBootApplication
public class Springboot10TaskApplication {

    public static void main(String[] args) {
        SpringApplication.run(Springboot10TaskApplication.class, args);
    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
3. 执行测试

运行启动类,每过0秒控制台输入
在这里插入图片描述

十七、Springboot整合Redis

SpringBoot 操作数据都是使用 ——SpringData
Spring官网:https://spring.io/
SpringBoot 操作数据:
在这里插入图片描述

SpringData也是和SpringBoot 齐名的项目
说明:在Springboot2.x之后,原来使用的Jedis被替换为了Lettuce

  • Jedis:采用的直连,多个线程操作,是不安全的,如果避免不安全使用Jedis Pool 连接池 !更像BIO模式
  • Lettuce:采用netty,实例可以在多个线程中进行共享,不存在线程不安全的情况,可以减少线程数量!更像Nio模式

1. 创建项目

在这里插入图片描述
选择依赖
在这里插入图片描述

2. 配置

# SpringBoot 所有的配置类,都有一个自动配置类 RedisAutoConfiguration
# 自动配置类都会绑定一个properties文件 RedisProperties
  • 1
  • 2

1. 查看配置类

在项目目录 External Libraries 下面,查找SpringBoot自动配置,找到RedisAutoConfiguration
在这里插入图片描述
点击属性类
在这里插入图片描述
查看Redis配置属性
在这里插入图片描述

2. 配置文件配置

1. 开启本地redis

查看密码windows 系统redis密码在redis.windows.conf 文件下的requirepass root
在这里插入图片描述
登录redis

D:\WorkSoftware\Redis>redis-cli.exe -h 127.0.0.1 -p 6379
127.0.0.1:6379> set kk 123
(error) NOAUTH Authentication required.
127.0.0.1:6379> auth root
OK
127.0.0.1:6379> set kk 123
OK
127.0.0.1:6379> get kk
"123"
127.0.0.1:6379>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
2. 配置SpringBoot 配置文件

路径:src/main/resources/application.properties
代码:



# SpringBoot 所有的配置类,都有一个自动配置类 RedisAutoConfiguration
# 自动配置类都会绑定一个properties文件 RedisProperties
#配置redis
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=root


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

3. 链接测试

路径:com/xxx/Springboot11JredisApplicationTests.java
代码:

package com.xxx;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisTemplate;

import javax.annotation.Resource;

@SpringBootTest
class Springboot11JredisApplicationTests {

    @Resource
   private RedisTemplate redisTemplate;

    @Test
    void contextLoads() {
        /** redisTemplate 操作不同的数据类型,API 和 Redis 中的是一样的
         * opsForValue 类似于 Redis 中的 String
         * opsForList 类似于 Redis 中的 List
         * opsForSet 类似于 Redis 中的 Set
         * opsForHash 类似于 Redis 中的 Hash
         * opsForZSet 类似于 Redis 中的 ZSet
         * opsForGeo 类似于 Redis 中的 Geospatial
         * opsForHyperLogLog 类似于 Redis 中的 HyperLogLog
         */

        // 除了基本的操作,常用的命令都可以直接通过redisTemplate操作,比如事务……

        // 和数据库相关的操作都需要通过连接操作
        //RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
        //connection.flushDb();

        redisTemplate.opsForValue().set("key", "呵呵");
        System.out.println(redisTemplate.opsForValue().get("key"));
    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

测试结果:
在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/192620
推荐阅读
相关标签
  

闽ICP备14008679号