You辉编程_有关boot

一、SpringBoot多环境配置

1.环境的配置信息

(1)application.properties

#指定默认使用dev的配置
spring.profiles.active=dev

 (2)application-dev.properties

#开发环境
server.port=8080
branch=dev

(3)application-prod.properties

#测试环境
server.port=8081
branch=test

2.测试类

package com.yh.bootev.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Author youHui
 * 检测当前使用的是哪个环境
 **/
@RestController
@RequestMapping("/test")
public class TestController {
    @Value("${branch}")
    private String branch;

    @GetMapping("/branch")
    public String test(){
        return branch;
    }

}

3.打包后在不同环境下运行

java -jar 你打包的jar包名.jar --spring.profiles.active=你要切换的环境
如:java -jar boot-ev-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod

二、SpringBoot devtools热部署配置(自动的不建议,对性能消耗大,建议手动的)

1.引入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
</dependency>

2.配置plugin :加入 pligin 且配置一个属性 fork true

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <fork>true</fork>
                </configuration>
            </plugin>
        </plugins>
    </build>

3.开启自动编译

选择 File | Settings | Compiler 命令,然后勾选 Build project automatically 复选框,低版本的 IDEA 请勾选 make project
automatically 复选框。
4. IDEA 设置运行程中,允许自动编译
操作: ctrl + shift + alt + / ,选择 Registry ,勾选勾上 Compiler autoMake allow when app running

5.重启IDEA即可实现热部署。 

三、SpringBoot过滤器

(一)快速了解过滤器

过滤器是基于Servlet实现的,在web开发中可以帮助过滤一些指定的url,可以过滤掉不需要的东西,比如:一些错误的请求。过滤未登录的用户等。

废话不多说直接上代码:

方式一:@WebFilter

1.创建过滤器

package com.yh.bootfilter.filter;


import org.springframework.core.annotation.Order;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * @Author youHui
 * 自定义Filter的方式有两种,一种是@WebFilter,另一种是FilterRegistrationBean
 *方式一:
 * @WebFilter用于将一个类声明为过滤器,该注解将在部署时被容器处理,
 * 容器会根据具体的属性配置将相应的类部署为过滤器
 * 其中的来个参数
 * urlPatterns = "/api/*":定义要拦截的url路径
 * filterName = "myFilter":指定过滤器的名称
 **/
@WebFilter(urlPatterns = "/api/*",filterName = "myFilter")
@Order(1) //这个值用来控制过滤的执行顺序,若同时有多个过滤器,该值越大,越往后执行
public class MyFilter implements Filter {//1.实现Filter接口
    //2.重写Filter的三个方法

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("MyFilter被初始化了");

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //获取所拦截的接口信息
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String uri = request.getRequestURI();
        String method = request.getMethod();
        System.out.println("请求的接口--"+uri+"请求的方法--"+method);
        filterChain.doFilter(servletRequest,servletResponse);//只用执行了这个方法,才会丸往下执行
    }

    @Override
    public void destroy() {
        System.out.println("MyFilter被销毁");
    }
}

2.测试类

package com.yh.bootfilter.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Author youHui
 **/
@RestController
@RequestMapping("/api")
public class FilterTestController {
    @GetMapping("/user/filter")
    public String hello(){
        return "我被myFilter过滤器监控了";
    }
}

3.注:需要在启动类中加

@ServletComponentScan注解过滤器才会生效

方式二:

通过FilterRegistrationBean注入容器的方式实现

1.创建过滤器类

package com.yh.bootfilter.filter;


import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * @Author youHui
 *FilterRegistrationBean
 **/

public class MyFilter2 implements Filter {//1.实现Filter接口
    //2.重写Filter的三个方法

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("MyFilter被初始化了");

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //获取所拦截的接口信息
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String uri = request.getRequestURI();
        String method = request.getMethod();
        System.out.println("请求的接口--"+uri+"请求的方法--"+method);
        filterChain.doFilter(servletRequest,servletResponse);//只用执行了这个方法,才会丸往下执行
    }

    @Override
    public void destroy() {
        System.out.println("MyFilter被销毁");
    }
}

2.创建配置类:目的是为了将过滤器信息注入到Spring容器中去

package com.yh.bootfilter.config;

import com.yh.bootfilter.filter.MyFilter2;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Author youHui
 **/
@Configuration
public class FilterConfig {

    //将过滤去注入到容器中
    @Bean
    public MyFilter2 myFilter2(){
        return new MyFilter2();
    }

    @Bean
    public FilterRegistrationBean getFilterRegistrationBean(MyFilter2 myFilter2){
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(myFilter2);//指定过滤器类
        filterRegistrationBean.setOrder(1);//过滤器的顺序
        filterRegistrationBean.addUrlPatterns("/api/*");//指定要拦截的接口
        filterRegistrationBean.setName("myFilter");//指定过滤器名
        return filterRegistrationBean;
    }
}

3.测试类

package com.yh.bootfilter.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Author youHui
 **/
@RestController
@RequestMapping("/api")
public class FilterTestController {
    @GetMapping("/user/filter")
    public String hello(){
        return "我被myFilter过滤器监控了";
    }
}

(二)过滤器在开发中的应用

1.配置开发性接口

在application.properties文件中:

#设置白名单接口:凡是请求地址层级带有open都放行
open.url=/**/open/**

2.过滤器 

package com.yh.bootfilter.filter;


import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * @Author youHui
 *FilterRegistrationBean
 **/

public class MyFilter2 implements Filter {//1.实现Filter接口
    @Value("${open.url}")
    private String openUrl;//获取开发性api
    //2.重写Filter的三个方法

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("MyFilter被初始化了");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //获取所拦截的接口信息
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String uri = request.getRequestURI();
        String method = request.getMethod();
        System.out.println("请求的接口--"+uri+"请求的方法--"+method);
        //判断是是开放性api
        AntPathMatcher antPathMatcher = new AntPathMatcher();
        if(antPathMatcher.match(openUrl,uri)){
            filterChain.doFilter(servletRequest,servletResponse);//放行
        }else {
            //如果不是开放的接口,就判断它是否有token凭证
            String token = request.getHeader("token");//获取token
            if(StringUtils.isEmpty(token)){
                //跳转到未登录的接口
                servletRequest.getRequestDispatcher("/api/open/unLogin").forward(servletRequest, servletResponse);
            }else {
                filterChain.doFilter(servletRequest,servletResponse);
            }
        }
    }

    @Override
    public void destroy() {
        System.out.println("MyFilter被销毁");
    }
}

3.

package com.yh.bootfilter.config;

import com.yh.bootfilter.filter.MyFilter2;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Author youHui
 **/
@Configuration
public class FilterConfig {

    //将过滤去注入到容器中
    @Bean
    public MyFilter2 myFilter2(){
        return new MyFilter2();
    }

    @Bean
    public FilterRegistrationBean getFilterRegistrationBean(MyFilter2 myFilter2){
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(myFilter2);//指定过滤器类
        filterRegistrationBean.setOrder(1);//过滤器的顺序
        filterRegistrationBean.addUrlPatterns("/api/*");//指定要拦截的接口
        filterRegistrationBean.setName("myFilter");//指定过滤器名
        return filterRegistrationBean;
    }
}

4.测试类

package com.yh.bootfilter.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

/**
 * @Author youHui
 **/
@RestController
@RequestMapping("/api")
public class FilterTestController {
    @GetMapping("/user/filter")
    public String hello(){
        return "我被myFilter过滤器监控了";
    }

    //开放性接口
    @GetMapping("/home/open/info")
    public String setHome(){
        return "欢迎进入首页";
    }

    @GetMapping("/open/unLogin")
    public String setUnLogin(){
        return "登录失效,请重新登录";
    }
}

四、SpringBoot拦截器Interceptor

简单来说,拦截器就是一道阀门,在某个方法被访问之前进行拦截,然后在之前或者之后加入某些操作,拦截器是AOP的一种实现策略。

(一)Interceptor基础

1.自定义拦截器类

package com.yh.bootinterceptor.interceptor;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

/**
 * @Author youHui
 **/
public class MyInterceptor implements HandlerInterceptor {//1.实现HandlerInterceptor接口

    //2.重写它的三个方法

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("拦截方法访问之前调用");
        String requestUri = request.getRequestURI();//获取被拦截的接口
        System.out.println(requestUri+"接口被拦截了");
        return true;
    }


    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("拦截方法访问之后调用");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("整个流程结束调用");
    }
}

2.定义开放的接口

#开发性接口
open.url=/**/open/**

3.创建配置类,用来配置拦截器的cel

package com.yh.bootinterceptor.config;

import com.yh.bootinterceptor.interceptor.MyInterceptor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @Author youHui
 **/
@Configuration
public class WebApplicationConfig implements WebMvcConfigurer {//1.实现WebMvcConfigurer
    //注入开放性api
    @Value("${open.url}")
    private String openUrl;
    //声明一个拦截器并注入到容器中
    @Bean
    public MyInterceptor myInterceptor(){
        return new MyInterceptor();
    }
    //2.重写addInterceptors方法
    @Override
    public void addInterceptors(InterceptorRegistry registry){
        /**
         * 配置拦截策略
         * addInterceptor(myInterceptor()):指定用哪一个拦截器
         * addPathPatterns("/api/**"):所要拦截的接口
         * excludePathPatterns(openUrl):开放接口
         */
        registry.addInterceptor(myInterceptor()).addPathPatterns("/api/**").excludePathPatterns(openUrl);
    }
}

4.测试类

package com.yh.bootinterceptor.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Author youHui
 **/
@RestController
@RequestMapping("/api")
public class InterceptorController {
    @GetMapping("/home/open/info")
    public String home(){
        return "欢迎访问首页";
    }

    @GetMapping("/user/interceptor")
    public String userInfo(){
        return "已经被拦截器监控";
    }
}

(二)拦截器在用户登录中的应用

1.配置类

package com.yh.bootinterceptor.config;

import com.yh.bootinterceptor.interceptor.MyInterceptor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @Author youHui
 **/
@Configuration
public class WebApplicationConfig implements WebMvcConfigurer {//1.实现WebMvcConfigurer
    //注入开放性api
    @Value("${open.url}")
    private String openUrl;
    //声明一个拦截器并注入到容器中
    @Bean
    public MyInterceptor myInterceptor(){
        return new MyInterceptor();
    }
    //2.重写addInterceptors方法
    @Override
    public void addInterceptors(InterceptorRegistry registry){
        /**
         * 配置拦截策略
         * addInterceptor(myInterceptor()):指定用哪一个拦截器
         * addPathPatterns("/api/**"):所要拦截的接口
         * excludePathPatterns(openUrl):开放接口
         */
        registry.addInterceptor(myInterceptor()).addPathPatterns("/api/**").excludePathPatterns(openUrl);
    }
}

2.拦截器类

package com.yh.bootinterceptor.interceptor;

import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @Author youHui
 **/
public class MyInterceptor implements HandlerInterceptor {//1.实现HandlerInterceptor接口

    //2.重写它的三个方法

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("拦截方法访问之前调用");
        String requestUri = request.getRequestURI();//获取被拦截的接口
        System.out.println(requestUri+"接口被拦截了");
        //判断用户是否携带凭证
        String token = request.getHeader("token");
        if(StringUtils.isEmpty(token)){
            request.getRequestDispatcher("/api/open/unLogin").forward(request,response);
            return false;
        }
        return true;
    }


    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("拦截方法访问之后调用");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("整个流程结束调用");
    }
}

3.测试类

package com.yh.bootinterceptor.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Author youHui
 **/
@RestController
@RequestMapping("/api")
public class InterceptorController {
    @GetMapping("/home/open/info")
    public String home(){
        return "欢迎访问首页";
    }

    @GetMapping("/user/interceptor")
    public String userInfo(){
        return "已经被拦截器监控";
    }

    @GetMapping("/open/unLogin")
    public String getUnLogin(){
        return "登录失效,请重新登录";
    }
}

五、SpringBoot整合JSP

1.添加jsp相关依赖

        <!--jsp标签库支持-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
        </dependency>

        <!--springBoot内置的tomcat对jsp的支持-->
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
        </dependency>

2.jsp相关配置

spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp
server.port=8088

3.配置webapp的路径(创建在main目录下)

4.在jsp文件夹下新建index.jsp文件


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1 style="color:blue;font-weight: bold;">成功整合jsp</h1>
</body>
</html>

 5.测试类

package com.yh.bootjsp.controller;

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

/**
 * @Author youHui
 **/
@Controller
@RequestMapping
public class JspController {
    @GetMapping("/index")
    public String index(){
        return "index";//返回jsp页面
    }
}

 六、SpringBoot整合Thymeleaf

1.Thymeleaf配置

spring.thymeleaf.prefix=classpath:/templates
spring.thymeleaf.suffix=.html
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.servlet.content-type=text/html

2.Thymeleaf依赖

在项目创建时勾选Thymeleaf或到网上找相关依赖引入即可。

3.在templates下创建模板index.html文件

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<p th:text="'hello:'+${username}"></p>
</body>
</html>

4.测试类

@Controller
public class HelloController {
    @GetMapping("/hello")
    public String hello(Model model){
        model.addAttribute("username","zhangsan");
        return "hello";
   }
}

七、SpringBoot整合Freemarker

我这里有提到(123条消息) You辉编程_Java框架之SpringBoot_You辉编程的博客-CSDN博客

八、SpringBoot集成Druid监控数据源

其实就是一个平台,通过配置进入平台查看一些数据。

推展认识:

1.Druid 是阿里巴开源平台上的一个项目,整个项目由数据库连接池、插件框架和 SQL 解析器组成,该项目主要是为了扩展 JDBC 的一
些限制,可以让程序员实现一些特殊的需求,比如统计 SQL 信息、 SQL 性能收集、 SQL 注入检查、 SQL 翻译等,程序员可以通过定制
来实现自己需要的功能。 Druid 首先是一个数据库连接池,但它不仅是一个数据库连接池,还包含了了一个 ProxyDriver ,一系列列内
置的 JDBC 组件库。在 Java 的世界中 Druid 是监控做的最好的数据库连接池,在功能、性能、扩展性方面,也有不错的表现。
2.Druid的作用
(1)替换其他 Java 连接池, Druid 提供了了一个高效、功能强大、可扩展性好的数据库连接池。
(2)可以监控数据库访问性能, Druid 内置提供了一个功能强大的 StatFilter 插件,能够详细统计 SQL 的执行性能,这对于线上分析数据库访问性能有很大帮助。
(3)SQL 执⾏日志, Druid 提供了不同的 LogFilter ,能够⽀支持 Common-Logging Log4j JdkLog ,可以按需要选择相应的 LogFilter,监控应用的数据库访问情况。
(4)扩展 JDBC ,如果你要对 JDBC 层有编程的需求,可以通过 Druid 提供的 Filter 机制,很方便编写 JDBC 层的扩展插件。
3.使用Durid
(1)引入依赖
 <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.10</version>
</dependency>

(2)相关配置

#数据库配置
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.druid.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.druid.url=jdbc:mysql://localhost:3306/test_mybatis?
useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.druid.username=root
spring.datasource.druid.password=root
##################    连接池配置    ################
#连接池建立时创建的初始化连接数
spring.datasource.druid.initial-size=5
#连接池中最大的活跃连接数
spring.datasource.druid.max-active=20
#连接池中最小的活跃连接数
spring.datasource.druid.min-idle=5
# 配置获取连接等待超时的时间
spring.datasource.druid.max-wait=60000
# 打开PSCache,并且指定每个连接上PSCache的大小
spring.datasource.druid.pool-prepared-statements=true
spring.datasource.druid.max-pool-prepared-statement-per-connection-size=20 spring.datasource.druid.validation-query=SELECT 1 FROM DUAL
spring.datasource.druid.validation-query-timeout=30000
#是否在获得连接后检测其可用性
spring.datasource.druid.test-on-borrow=false
#是否在连接放回连接池后检测其可用性
spring.datasource.druid.test-on-return=false
#是否在连接空闲一段时间后检测其可用性
spring.datasource.druid.test-while-idle=true
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
spring.datasource.druid.time-between-eviction-runs-millis=60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
spring.datasource.druid.min-evictable-idle-time-millis=300000
# 监控后台账号和密码
spring.datasource.druid.stat-view-servlet.login-username=admin
spring.datasource.druid.stat-view-servlet.login-password=66666
spring.devtools.restart.poll-interval=3000ms
spring.devtools.restart.quiet-period=2999ms

(3)访问Druid:http://localhost:8080/druid

九、SpringBoot集成Swagger2

(一)使用

1.引入依赖

        <!--swagger2 依赖-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
        </dependency>

2.创建配置

@Configuration
@EnableSwagger2
public class SwaggerConfig {
    
    @Bean
    public Docket createDocket(){
       
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                //要暴露的接口
                .apis(RequestHandlerSelectors.basePackage("com.xxx.xxx.controller"))
                .paths(PathSelectors.any())
                .build()
                .globalOperationParameters(parameterList)
    }
    
    //信息的描述
    private ApiInfo apiInfo(){
        return new ApiInfoBuilder().
                title("Swagger api") //标题
                .description("spring boot 2.x 集成Swagger") //描述
                .version("1.0") //版本
                .build();
    }
}

3.描述

@Data
public class SwaggerReqVO {
    @ApiModelProperty(value = "账号") //描述
    private String username;
    @ApiModelProperty(value = "密码")
    private String password;
}

4.测试类

@RestController
@RequestMapping("/api")
@Api(tags = "测试swagger接口") //描述
public class SwaggerController {
    @ApiOperation(value = "我的第一个swagger接口")
    @PostMapping("/swagger")
    public SwaggerReqVO testSwagger(@RequestBody SwaggerReqVO vo){
     return vo;
    }
}

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

 (二)Swagger常用注解

1.@Api:对一个类进行说明。可以标记一个 Controller 类作为 Swagger 文档资源。

@Api(tags = "用户模块",description = "用户模块相关接口") 

2.@ApiModel:对一个类进行说明。一般用于接受前端参数的实体类上。

@ApiModel(value = "实体类的相对路径",description = "接收更新用户数据VO")
public class UpdateUserReqVO {
    @ApiModelProperty(value = "用户id")//对每个属性进行描述
    private String id;

    @ApiModelProperty(value = "账号")
    private String username;

    @ApiModelProperty(value = "密码")
    private String password;

    @ApiModelProperty(value = "性别(1.男 2.女)")
    private Integer sex;
}

3.@ApiParam:主要用于Controller中方法参数的说明

value:参数说明

required:是否是必须的

@GetMapping("/getUser")
    public SysUser getUser(@ApiParam(value = "需要传用户id",required = true) @RequestParam(required = true) String id){
        return userService.getUserInfo(id);
    }

4.@ApiOperation:对controller方法的作用进行说明。

@ApiOperation(value = "获取一个用户")

5.@ApiResponse和ApiResponses

@ApiResponse用来说明响应的是哪些信息,ApiResponses表示组装了多个@ApiResponse

 @ApiResponses({
            @ApiResponse(code = 0,message = "响应成功",response = SysUser.class)
    })

6.@ApiImplicitParam和@ApiImplicitParams

用于方法,为单独的请求参数进行说明。

@ApiImplicitParams({
            @ApiImplicitParam(name="id",value = "用户id",dataType = "String",paramType = "query",required = true,
            defaultValue = "1001")
    })

(三)Swagger安全配置

有的环境并不需要Swagger,这时我们可以将其关掉。

1.配置

#swagger 开关
swagger2.enable=true

2.将其注入配置类

@Configuration
@EnableSwagger2
public class SwaggerConfig {
    @Value("${swagger2.enable}")
    private boolean enable;
    @Bean
    public Docket createDocket(){
       
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                //要暴露的接口
                .apis(RequestHandlerSelectors.basePackage("com.xxx.xxx.controller"))
                .paths(PathSelectors.any())
                .build()
                .globalOperationParameters(parameterList)
                .enable(enable);
    }
    
    //信息的描述
    private ApiInfo apiInfo(){
        return new ApiInfoBuilder().
                title("Swagger api") //标题
                .description("spring boot 2.x 集成Swagger") //描述
                .version("1.0") //版本
                .build();
    }
}

(四)Swagger的全局配置

如果想Swagger也能像PostMan一样可以加一些头部信息的话,就需要对Swagger进行全局配置

@Configuration
@EnableSwagger2
public class SwaggerConfig {
    @Value("${swagger2.enable}")
    private boolean enable;
    @Bean
    public Docket createDocket(){

        List<Parameter> parameterList=new ArrayList<>();
        ParameterBuilder parameterBuilder=new ParameterBuilder();//头部信息
        parameterBuilder.name("token").description("swagger调试(模拟传入用户认证凭证)").modelRef(new ModelRef("String"))
                .parameterType("header").required(false);
        parameterList.add(parameterBuilder.build());

        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                //要暴露的接口
                .apis(RequestHandlerSelectors.basePackage("com.yingxue.lesson.web.controller"))
                .paths(PathSelectors.any())
                .build()
                .globalOperationParameters(parameterList)
                .enable(enable);
    }

    //信息的描述
    private ApiInfo apiInfo(){
        return new ApiInfoBuilder().
                title("Swagger api") //标题
                .description("spring boot 2.x 集成Swagger") //描述
                .version("1.0") //版本
                .build();
    }
}

 十、SpringBoot封装整合Redis

1.初始Redis:You辉编程_Redis数据库_You辉编程的博客-CSDN博客

2.Srpingboot+jedis

jedis集成了redis的命令擦操作,jedis是redis官方推荐面向Java操作Redis的客户端 。

(1)引入相关依赖

        <!--springboot封装redis的组件依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!--jedis客户端-->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>

(2)配置jedisPool连接池管理jedis

#jedisPool的配置开始

# 连接池中的最大空闲连接
redis.maxIdle=30
# 连接池中的最小空闲连接
redis.minIdle=1
#连接池最大连接数(使用负值表示没有限制)
redis.maxTotal=100
# 连接池最大阻塞等待时间(使用负值表示没有限制)10秒redis.maxWait=10000
# Redis服务器地址
redis.host=localhost
# Redis服务器连接端口
redis.port=6379
# Redis链接超时时间 10秒
redis.timeout=10000

(3)配置类

package com.yh.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
 * @Author youHui
 **/
@Configuration
public class RedisConfig {
    @Value("${redis.maxIdle}")
    private int maxIdle;
    @Value("${redis.minIdle}")
    private int minIdle;
    @Value("${redis.maxTotal}")
    private int maxTotal;
    @Value("${redis.timeout}")
    private int timeout;
    @Value("${redis.maxWait}")
    private int maxWait;
    @Value("${redis.host}")
    private String host;
    @Value("${redis.port}")
    private int port;

    /**
     * 把 jedisPool连接池注入到spring容器中
     * @return
     */
    @Bean
    public JedisPool getJedisPool(){
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxIdle(maxIdle);
        jedisPoolConfig.setMinIdle(minIdle);
        jedisPoolConfig.setMaxTotal(maxTotal);
        jedisPoolConfig.setMaxWaitMillis(maxWait);

        JedisPool jedisPool = new JedisPool(jedisPoolConfig,host,port,timeout);
        return jedisPool;
    }

}

(4)创建RedisService类,jedis企业开发工具类的封装

package com.yh.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

/**
 * @Author youHui
 **/
@Service
public class RedisService {
    //注入连接池
    @Autowired
    private JedisPool jedisPool;

    public boolean exists(String key){
        Jedis jedis = null;
        boolean result;
        try {
            jedis = jedisPool.getResource();
            result = jedis.exists(key);
        } finally {
            if(jedis != null){
                jedis.close();
            }
        }
        return result;
    }

    public Long del(final String... keys){
        Jedis jedis = null;
        Long result;
        try {
            jedis = jedisPool.getResource();
            result = jedis.del(keys);
        } finally {
            if(jedis != null){
                jedis.close();
            }
        }
        return result;
    }
}

(5)测试

    @Autowired
    private RedisService redisService;

    @Test
    public void testRedis(){
        redisService.exists("name");
        redisService.del("name","name1");
    }

3.SpringBoot+RedisRedisTemplate工具类封装自定义序列化方式

RedisTemplate类是对Redis api进一步进行封装,使操作Redis更加便捷。

(1)引入相关依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

(2)配置

# Redis 服务器地址
spring.redis.host=localhost
# Redis 服务器连接端⼝
spring.redis.port=6379
# 连接池最大连接数(使用负值表示没有限制)默认 8
spring.redis.lettuce.pool.max-active=100
# 连接池最大阻塞等待时间(使用负值表示没有限制)默认 -1 spring.redis.lettuce.pool.max-wait=PT10S
# 连接池中的最大空闲连接默认 8
spring.redis.lettuce.pool.max-idle=30
# 连接池中的最小空闲连接默认 0
spring.redis.lettuce.pool.min-idle=1
#链接超时时间
spring.redis.timeout=PT10S

(3)测试

SpirngBoot已经自动把RedisTemplate注入到Spring容器中,直接拿来用即可。并提供了一下方法

opsForValue();// 操作字符串
opsForHash();// 操作 hash
opsForList();// 操作 list
opsForSet();// 操作 set
opsForZSet();// 操作有序 set
    @Test
    public void testRedis(){
        redisTemplate.opsForValue().get("name");
        //指定序列化,使它的key,value可读即显示正常的字符
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new StringRedisSerializer());
        redisTemplate.opsForValue().set("name","赵六");
    }

注:RedisTemplate默认只支持String类型的数据,要想支持除String以外的数据,则要自己定义序列化方式(需要引入fast json依赖)。 

          <!--fastJson-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.49</version>
        </dependency>

自定义序列化方式代码

public class MyStringRedisSerializer implements RedisSerializer<Object> {
    private final Charset charset;

    public MyStringRedisSerializer() {
        this(StandardCharsets.UTF_8);
    }

    public MyStringRedisSerializer(Charset charset) {
        Assert.notNull(charset, "Charset must not be null!");
        this.charset = charset;
    }

    @Override
    public String deserialize(byte[] bytes) {
        return (bytes == null ? null : new String(bytes, charset));
    }

    @Override
    public byte[] serialize(Object object) {
        if (object == null) {
            return new byte[0];
        }
        if(object instanceof String){
            return object.toString().getBytes(charset);
        }else {
            String string = JSON.toJSONString(object);
            return string.getBytes(charset);
        }

    }



}

封装成工具类

package com.yh.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

/**
 * @Author youHui
 **/
@Service
public class RedisService {
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;
    
    public boolean hasKey(String key){
        if(key == null){
            return false;
        }
        return redisTemplate.hasKey(key);
    }
}

配置类

package com.yh.config;

import com.yh.serializer.MyStringRedisSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * @Author youHui
 **/
@Configuration
public class RedisConfig {
    
    @Bean
    public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
        RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new MyStringRedisSerializer());
        redisTemplate.setHashValueSerializer(new MyStringRedisSerializer());
        return redisTemplate;
    }
}

异常类

package com.yh.exception;

/**
 * @Author youHui
 **/
public class BusinessExcception extends RuntimeException{
    private final int messageCode;
    private final String messageDefault;

    public BusinessExcception(String message,int messageCode) {
        super(message);
        this.messageCode = messageCode;
        this.messageDefault = message;
    }

    public int getMessageCode() {
        return messageCode;
    }

    public String getMessageDefault() {
        return messageDefault;
    }
}

测试

     @Autowired
    private RedisService redisService;

    @Test
    public void testRedis(){
//        redisTemplate.opsForValue().get("name");
//        //指定序列化,使它的key,value可读即显示正常的字符
//        redisTemplate.setKeySerializer(new StringRedisSerializer());
//        redisTemplate.setValueSerializer(new StringRedisSerializer());
//        redisTemplate.opsForValue().set("name","赵六");
        System.out.println(redisService.hasKey("name"));
    }

4.SpringBoot redis实战-分布式Session共享

实现思路

用户提交用户名+密码--->登录成功后生成token--->把用户信息存入Redis(key就是token,value就是userId)--->设置key的过期时间(模拟Session的过期时间,一般我1h)--->拦截器拦截请求校验sessionId

boot-redis-session: redis实行分布式session共享 (gitee.com)

十一、SpringBoot集成定时任务、异步调用

1.定时任务实现方式

注:需要在启动类中加

@EnableScheduling //开启定时任务
package com.yh.bootschedule.task;

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

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @Author youHui
 **/
@Component
public class SchedulerTask {
    private static final SimpleDateFormat f=new SimpleDateFormat("HH:mm:ss");

    /**
     * @Scheduled(fixedRate = 5000) :上一次开始执行时间点之后5秒再执行
     * @Scheduled(fixedDelay = 5000) :上一次执行完毕时间点之后5秒再执行
     * @Scheduled(initialDelay=1000, fixedRate=5000) :第一次延迟1秒后执行,之后按fixedRate的规则每5秒执行一次
     */
    //方式一
    //定时任务5秒执行一次
//    @Scheduled(fixedRate = 5000)
//    public void processFixedRate(){
//        System.out.println("processFixedRate方式:开始定时任务,现在的时间是:"+f.format(new Date()));
//    }

    /**
     * cron 一共有七位,最后一位是年,Spring Boot 定时方案中只需要设置六位即可:
     * 第一位,表示秒,取值 0 ~ 59; 第二位,表示分,取值 0 ~ 59; 第三位,表示小时,取值 0 ~ 23; 第四位,日期天/日,取值 1 ~
     * 31; 第五位,日期月份,取值 1~12; 第六位,星期,取值 1 ~ 7,星期一,星期二...,注,1 表示星期 天,2 表示星期一; 第七位,
     * 年份,可以留空,取值 1970 ~ 2099。 cron 中,还有一些特殊的符号,含义如下: (*)星号,可以理解为每的意思,每秒、每分、
     * 每天、每月、每年...。 (?)问号,问号只能出现在日期和星期这两个位置,表示这个位置的值不确定。 (-)减号,表达一个范围,
     * 如在小时字段中使用“10 ~ 12”,则表示从 10 到 12 点,即 10、11、12。 (,)逗号,表达一个列表值,如在星期字段中使用“1、2、
     * 4”,则表示星期一、星期二、星期四。 (/)斜杠,如 x/y,x 是开始值,y 是步⻓长,比如在第一位(秒),0/15 就是从 0 秒开始,
     * 每隔 15 秒执 行一次。 下面列举几个常用的例子。 0 0 1 * * ? :每天凌晨1 点执行; 0 5 1 * * ?:每天 凌晨1 点 5 分执行;
     * 以上就是 Spring Boot 自定的定时方案,使用起来非常的简单方便。
     */


    //方式二
    @Scheduled(cron="*/5 * * * * ?")
    private void processCron(){
        System.out.println("processCron方式:定时任务开始运行,现在时间:" + f.format(new Date()));
    }
}

2.SpringBoot使用@Async实现异步调用-异步回调结果

注:需要在启动类中添加@EnableAsync注解

package com.yh.task;

import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Component;

import java.util.Random;
import java.util.concurrent.Future;

/**
 * @Author youHui
 **/
@Component
public class AsyncTask {
    /**
     * 这是同步
     */
    public static Random random=new Random();

    @Async
    public Future<String> doTaskOne() throws Exception{
        System.out.println("开始任务一");
        long startTime=System.currentTimeMillis();//当前时间
        Thread.sleep(random.nextInt(100000));
        long endTime=System.currentTimeMillis();
        System.out.println("完成任务一消耗的时间:"+(endTime-startTime)+"毫秒");
        return new AsyncResult<>("任务一已完成");
    }

    @Async
    public Future<String>  doTaskTwo() throws Exception{
        System.out.println("开始任务二");
        long startTime=System.currentTimeMillis();//当前时间
        Thread.sleep(random.nextInt(100000));
        long endTime=System.currentTimeMillis();
        System.out.println("完成任务二消耗的时间:"+(endTime-startTime)+"毫秒");
        return new AsyncResult<>("任务一已完成");
    }

    @Async

    public Future<String>  doTaskThree() throws Exception{
        System.out.println("开始任务三");
        long startTime=System.currentTimeMillis();//当前时间
        Thread.sleep(random.nextInt(100000));
        long endTime=System.currentTimeMillis();
        System.out.println("完成任务三消耗的时间:"+(endTime-startTime)+"毫秒");
        return new AsyncResult<>("任务一已完成");
    }
}

测试:

@Test
    public void testTask() throws Exception{
        Future<String> taskOne=asyncTask.doTaskOne();
        Future<String> taskTwo=asyncTask.doTaskTwo();
        Future<String> taskThree=asyncTask.doTaskThree();

        while (true){
            if(taskOne.isDone()&&taskTwo.isDone()&&taskThree.isDone()){
                //代处理完后统一返回结果集
                break;
            }
            Thread.sleep(10000);
        }
    }

3.SpringBoot使用@Async实现异步调用-自定义线程池

使用@EnableAsync+@Async默认实现SimpleAsyncTaskExecutor 不是真的线程池,这个类不重用线程,每次调用 都会创建一个新的线程,非常的消耗资源。

(1)注入线程池对象

package com.yh;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

@SpringBootApplication
public class BootAsyncApplication {

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

    @Bean
    public Executor myTaskExecutor(){
        ThreadPoolTaskExecutor executor=new ThreadPoolTaskExecutor();
        //创建线程池,并初始化线程数量
        executor.setCorePoolSize(10);
        //最大线程数
        executor.setMaxPoolSize(15);
        //用来缓冲执行任务的队列
        executor.setQueueCapacity(200);
        //当超过核心先线程数之外的线程在空闲时间到达之后就会被销毁
        executor.setKeepAliveSeconds(60);
        //设置好之后可以方便定位处理任务所在的线程池
        executor.setThreadNamePrefix("myTask");
        //用来设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean
        executor.setWaitForTasksToCompleteOnShutdown(true);
        //该方法用来设置线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住。
        executor.setAwaitTerminationSeconds(60);
        //线程池对拒绝任务的处理策略:这里采用了CallerRunsPolicy策略,当线程池没有处理能力的时候,该策略会直接在execute 方法的调用线程中运行被拒绝的任务;如果执行程序已关闭,则会丢弃该任务
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }

}
package com.yh.task;

import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Component;

import java.util.Random;
import java.util.concurrent.Future;

/**
 * @Author youHui
 **/
@Component
public class AsyncTask {
    /**
     * 这是同步
     */
    public static Random random=new Random();

    @Async("myTaskExecutor")
    public Future<String> doTaskOne() throws Exception{
        System.out.println("开始任务一");
        long startTime=System.currentTimeMillis();//当前时间
        Thread.sleep(random.nextInt(100000));
        long endTime=System.currentTimeMillis();
        System.out.println("完成任务一消耗的时间:"+(endTime-startTime)+"毫秒");
        return new AsyncResult<>("任务一已完成");
    }

    @Async("myTaskExecutor")
    public Future<String>  doTaskTwo() throws Exception{
        System.out.println("开始任务二");
        long startTime=System.currentTimeMillis();//当前时间
        Thread.sleep(random.nextInt(100000));
        long endTime=System.currentTimeMillis();
        System.out.println("完成任务二消耗的时间:"+(endTime-startTime)+"毫秒");
        return new AsyncResult<>("任务一已完成");
    }

    @Async("myTaskExecutor")
    public Future<String>  doTaskThree() throws Exception{
        System.out.println("开始任务三");
        long startTime=System.currentTimeMillis();//当前时间
        Thread.sleep(random.nextInt(100000));
        long endTime=System.currentTimeMillis();
        System.out.println("完成任务三消耗的时间:"+(endTime-startTime)+"毫秒");
        return new AsyncResult<>("任务一已完成");
    }
}
@Test
    public void testTask() throws Exception{
        Future<String> taskOne=asyncTask.doTaskOne();
        Future<String> taskTwo=asyncTask.doTaskTwo();
        Future<String> taskThree=asyncTask.doTaskThree();

        while (true){
            if(taskOne.isDone()&&taskTwo.isDone()&&taskThree.isDone()){
                //代处理完后统一返回结果集
                break;
            }
            Thread.sleep(10000);
        }
    }

十二、SpringBoot权限框架Shiro

shiro apache的一个开源框架,而且呢是一个权限管理的框架,用于实现用户认证、用户授权。
spring 中也有一个权限框架 spring security (原名 Acegi) ,它和 spring 依赖过于紧密,没有 shiro 使用简单。 shiro 不依赖于 spring shiro 不仅可以实现 web 应用的权限 管理,还可以实现c/s 系统,分布式系统权限管理, shiro 属于轻量框架,越来越多企业项目开始使用 shiro 。使用 shiro 实现系统的权限 管理,有效提高开发效率,从而降低开发成本。
subject:主体,可以是用户也可以是程序,主体要访问系统,系统需要对主体进行认证、授权。
security Manager:安全管理器,主体进行认证和授权都是通过securityManager进行。
authenticator:认证器,主体进行认证最终通过authenticator进行的。
authorizer:授权器,主体进行授权最终通过authorizer进行的。
sessionManager:web应用中一般是用web容器对session进行管理,shiro也提供一套session管理的方式。
SessionDao: 通过SessionDao管理session数据,针对个性化的session数据存储需要使用sessionDao。
cache Manager:缓存管理器,主要对session和授权数据进行缓存,比如将授权数据通过cacheManager进行缓存管理,和
ehcache整合对缓存数据进行管理。
Cryptography:加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储。
realm:域,领域,相当于数据源,通过realm存取认证、授权相关数据。
记住一点,Shiro 不会去维护用户、维护权限;这些需要我们自己去设计/提供;然后通过相应的接口注入给Shiro 即可。

1.SpringBoot集成Shiro
(1)加入shiro依赖
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.1</version>
        </dependency>

(2)用户认证

public void authentication(){
        /*****************安全管理器环境**************************/
        //构建安全管理器环境SecurityManager环境
        DefaultWebSecurityManager defaultWebSecurityManager=new DefaultWebSecurityManager();
        //创建数据源
        SimpleAccountRealm simpleAccountRealm=new SimpleAccountRealm();
        simpleAccountRealm.addAccount("zhangwuji","666666");
        //设置到安全管理器
        defaultWebSecurityManager.setRealm(simpleAccountRealm);
        //把安全管理器配置到工具包里
        SecurityUtils.setSecurityManager(defaultWebSecurityManager);
        /*****************安全管理器环境**************************/


        /*****************主体提交验证**************************/
        //获取主体
        Subject subject = SecurityUtils.getSubject();
        //创建主体提交时需要携带的token(由用户名密码组成)
        UsernamePasswordToken usernamePasswordToken=new UsernamePasswordToken("zhangwuji","666666");

        try {
            //主体提交验证
            subject.login(usernamePasswordToken);
            /*****************主体提交验证**************************/
            //验证通过返回true,不通过返回false
            System.out.println("用户认证的状态"+subject.isAuthenticated());
            //退出
            subject.logout();
            System.out.println("用户认证的状态"+subject.isAuthenticated());
        }catch (UnknownAccountException uae){
            System.out.println("用户不存在");
        }catch (IncorrectCredentialsException ice){
            System.out.println("用户名密码不匹配");
        }catch (LockedAccountException lae){
            System.out.println("账号已经被锁定");
        }catch (AuthenticationException ae){
            System.out.println("用户名密码不匹配");
        }

    }

(2)用户授权

public void authorization(){
        /*****************安全管理器环境**************************/
        //构建安全管理器环境SecurityManager环境
        DefaultWebSecurityManager defaultWebSecurityManager=new DefaultWebSecurityManager();
        //创建数据源
        SimpleAccountRealm simpleAccountRealm=new SimpleAccountRealm();
        simpleAccountRealm.addAccount("zhangwuji","666666","admin","test");//更具角色授权
        //设置到安全管理器
        defaultWebSecurityManager.setRealm(simpleAccountRealm);
        //把安全管理器配置到工具包里
        SecurityUtils.setSecurityManager(defaultWebSecurityManager);
        /*****************安全管理器环境**************************/
        /*****************主体提交验证**************************/
        //获取主体
        Subject subject = SecurityUtils.getSubject();
        //创建主体提交时需要携带的token(由用户名密码组成)
        UsernamePasswordToken usernamePasswordToken=new UsernamePasswordToken("zhangwuji","666666");

        try {
            //主体提交验证
            subject.login(usernamePasswordToken);
            /*****************主体提交验证**************************/
            //验证通过返回true,不通过返回false
            System.out.println("用户认证的状态"+subject.isAuthenticated());
            //判断该用户是否拥有这个角色
            subject.checkRoles("admin","user");
            //退出
            subject.logout();
            System.out.println("用户认证的状态"+subject.isAuthenticated());
        }catch (UnknownAccountException uae){
            System.out.println("用户不存在");
        }catch (IncorrectCredentialsException ice){
            System.out.println("用户名密码不匹配");
        }catch (LockedAccountException lae){
            System.out.println("账号已经被锁定");
        }catch (AuthenticationException ae){
            System.out.println("用户名密码不匹配");
        }catch (UnauthorizedException e){
            System.out.println("该用户没有该权限访问");
        }
    }

(3)SpringBoot使用IniRealm进行认证授权

SimpleAccountRealm写死了用户数据,不够灵活,IniRealm是Shiro提供一种Realm实现。用户、角色、权限等信息集中在一个.ini文件里。

①配置.ini文件

在resources目录下创建一个shiro.ini文件(角色的配置文件)

[users] ----->用户的角色
test=666666,test
admin=66666,admin

[roles]------->用户的权限
test=user:list,user:edit
admin=*

②读取角色信息并认证授权

public void testIniRealm(){
        DefaultWebSecurityManager defaultWebSecurityManager=new DefaultWebSecurityManager();
        //读取配置文件的内容
        IniRealm iniRealm=new IniRealm("classpath:shiro.ini");
        defaultWebSecurityManager.setRealm(iniRealm);
        SecurityUtils.setSecurityManager(defaultWebSecurityManager);


        /*****************主体提交验证**************************/
        //获取主体
        Subject subject = SecurityUtils.getSubject();
        //创建主体提交时需要携带的token(由用户名密码组成)
        UsernamePasswordToken usernamePasswordToken=new UsernamePasswordToken("test","666666");

        try {
            //主体提交验证
            subject.login(usernamePasswordToken);
            /*****************主体提交验证**************************/
            //验证通过返回true,不通过返回false
            System.out.println("用户认证的状态"+subject.isAuthenticated());
            //判断该用户是否拥有这个角色
            subject.checkRoles("test");
            //校验是否拥有其权限
            subject.checkPermissions("user:list");//是否拥有用户列表的权限
            //退出
            subject.logout();
            System.out.println("用户认证的状态"+subject.isAuthenticated());
        }catch (UnknownAccountException uae){
            System.out.println("用户不存在");
        }catch (IncorrectCredentialsException ice){
            System.out.println("用户名密码不匹配");
        }catch (LockedAccountException lae){
            System.out.println("账号已经被锁定");
        }catch (AuthenticationException ae){
            System.out.println("用户名密码不匹配");
        }catch (UnauthorizedException e){
            System.out.println("该用户没有该权限访问");
        }

    }

(4)SpringBoot使用JdbcRealm进行认证授权

IniRealm虽然可以通过.ini文件进行配置然后读取其安全信息,但还是得提前写好相关信息,还是不够灵活,JdbcRealm可以直接从db中读取信息,然后再认证授权认证。

①加入数据库相关依赖

         <!--数据库-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--数据源-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.10</version>
        </dependency>

②用户权限信息

③认证授权

public void testJdbcRealm(){
        //配置数据源
        DruidDataSource druidDataSource=new DruidDataSource();
        druidDataSource.setUrl("jdbc:mysql://localhost:3306/shiro");
        druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
        druidDataSource.setUsername("root");
        druidDataSource.setPassword("666666");
        //配置文件中的用户权限信息
        JdbcRealm jdbcRealm=new JdbcRealm();
        jdbcRealm.setDataSource(druidDataSource);
        //开启权限开关
        jdbcRealm.setPermissionsLookupEnabled(true);

        //构建SecurityManager环境
        DefaultSecurityManager defaultSecurityManager=new DefaultWebSecurityManager();
        //设置Realm
        defaultSecurityManager.setRealm(jdbcRealm);
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        /*****************主体提交验证**************************/
        //获取主体
        Subject subject = SecurityUtils.getSubject();
        //创建主体提交时需要携带的token(由用户名密码组成)
        UsernamePasswordToken usernamePasswordToken=new UsernamePasswordToken("test","123456");

        try {
            //主体提交验证
            subject.login(usernamePasswordToken);
            /*****************主体提交验证**************************/
            //验证通过返回true,不通过返回false
            System.out.println("用户认证的状态"+subject.isAuthenticated());
            //判断该用户是否拥有这个角色
            subject.checkRoles("test");
            //校验是否拥有其权限
            subject.checkPermissions("user:deleted","role:list");//是否拥有用户列表的权限
            //退出
            subject.logout();
            System.out.println("用户认证的状态"+subject.isAuthenticated());
        }catch (UnknownAccountException uae){
            System.out.println("用户不存在");
        }catch (IncorrectCredentialsException ice){
            System.out.println("用户名密码不匹配");
        }catch (LockedAccountException lae){
            System.out.println("账号已经被锁定");
        }catch (AuthenticationException ae){
            System.out.println("用户名密码不匹配");
        }catch (UnauthorizedException e){
            System.out.println("该用户没有该权限访问");
        }
    }

 (5)Springboot使用自定义Realm进行认证授权

JdbcRealm虽然能从数据库读取用户授权信息,但其底层已经固定写好了sql语句,一旦数据库名或表名发生改变有得重新改写底层sql这样一来就造成不灵活,自定义Realm可以解决这个问题。

Realm只需要继承:AuthorizingRealm重写doGetAuthenticationfo(用户认证)、doGetAuthorizationInfo(用户授权)这两个方法即可。

①自定义Realm

package com.yh.shiro;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
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.springframework.util.StringUtils;

import javax.swing.text.SimpleAttributeSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author youHui
 **/
public class CustomRealm extends AuthorizingRealm {
    /**
     * mock用户信息
     * @param principalCollection
     * @return
     */
    /************************数据*************************/
    private Map<String,String> userMap=new HashMap<>();
    {
        userMap.put("admin","123456");
        userMap.put("test","123456");
    }
    /************************数据*************************/
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //用户授权
        String username = (String) principalCollection.getPrimaryPrincipal();
        //获取角色信息
        List<String> roles=getRolesByUserName(username);
        List<String> permissions=getPermissionsByUsername(username);
        SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
        info.addRoles(roles);
        info.addStringPermissions(permissions);
        return info;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //获取用户数据
        String username = (String) authenticationToken.getPrincipal();
        String password = getPasswordByUsername(username);
        if(StringUtils.isEmpty(password)){
            return null;
        }

        //用户认证
        SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(username,password,getName());
        return info;
    }

    //通过用户名获取到密码
    private String getPasswordByUsername(String username){
        return userMap.get(username);
    }

    //通过用户名获取角色信息
    private List<String> getRolesByUserName(String username){
        List<String> roles=new ArrayList<>();
        if(username.equals("admin")){
            roles.add("admin");
        }else {
            roles.add("test");
        }
        return roles;
    }

    //通过用户名获取权限信息
    private List<String> getPermissionsByUsername(String username){
        List<String> permissions=new ArrayList<>();
        if(username.equals("admin")){
            permissions.add("*");//权限为所有
        }
        permissions.add("user:list");
        permissions.add("user:deleted");
        permissions.add("user:edit");
        return permissions;
    }
}

②认证授权

public void testCustomRealm(){
        DefaultWebSecurityManager defaultWebSecurityManager=new DefaultWebSecurityManager();
        //创建域
        CustomRealm customRealm=new CustomRealm();
        defaultWebSecurityManager.setRealm(customRealm);
        SecurityUtils.setSecurityManager(defaultWebSecurityManager);


        /*****************主体提交验证**************************/
        //获取主体
        Subject subject = SecurityUtils.getSubject();
        //创建主体提交时需要携带的token(由用户名密码组成)
        UsernamePasswordToken usernamePasswordToken=new UsernamePasswordToken("test","123456");

        try {
            //主体提交验证
            subject.login(usernamePasswordToken);
            /*****************主体提交验证**************************/
            //验证通过返回true,不通过返回false
            System.out.println("用户认证的状态"+subject.isAuthenticated());
            //判断该用户是否拥有这个角色
            subject.checkRoles("test");
            //校验是否拥有其权限
            subject.checkPermissions("user:deleted","role:list");//是否拥有用户列表的权限
            //退出
            subject.logout();
            System.out.println("用户认证的状态"+subject.isAuthenticated());
        }catch (UnknownAccountException uae){
            System.out.println("用户不存在");
        }catch (IncorrectCredentialsException ice){
            System.out.println("用户名密码不匹配");
        }catch (LockedAccountException lae){
            System.out.println("账号已经被锁定");
        }catch (AuthenticationException ae){
            System.out.println("用户名密码不匹配");
        }catch (UnauthorizedException e){
            System.out.println("该用户没有该权限访问");
        }
    }

(6)SpringBoot整合shiro——盐值加密

①自定义Realm

package com.yh.shiro;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.util.StringUtils;

import javax.swing.text.SimpleAttributeSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author youHui
 **/
public class CustomRealm extends AuthorizingRealm {
    /**
     * mock用户信息
     * @param principalCollection
     * @return
     */
    /************************数据*************************/
    private Map<String,String> userMap=new HashMap<>();
    {
        userMap.put("admin","123456");
        userMap.put("test","123456");
    }
    /************************数据*************************/
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //用户授权
        String username = (String) principalCollection.getPrimaryPrincipal();
        //获取角色信息
        List<String> roles=getRolesByUserName(username);
        List<String> permissions=getPermissionsByUsername(username);
        SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
        info.addRoles(roles);
        info.addStringPermissions(permissions);
        return info;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
            throws AuthenticationException {
        //获取用户数据
        String username = (String) authenticationToken.getPrincipal();
        String password = getPasswordByUsername(username);
        if(StringUtils.isEmpty(password)){
            return null;
        }

        //用户认证
        // info=new SimpleAuthenticationInfo(username,password,getName());
        //SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(username,getEncPassword(password),getName());
        SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(
                username,getEncPassword(password,username),getName());
        //设置盐值
        info.setCredentialsSalt(ByteSource.Util.bytes(username));
        return info;
    }

    //通过用户名获取到密码
    private String getPasswordByUsername(String username){
        return userMap.get(username);
    }

    //通过用户名获取角色信息
    private List<String> getRolesByUserName(String username){
        List<String> roles=new ArrayList<>();
        if(username.equals("admin")){
            roles.add("admin");
        }else {
            roles.add("test");
        }
        return roles;
    }

    //通过用户名获取权限信息
    private List<String> getPermissionsByUsername(String username){
        List<String> permissions=new ArrayList<>();
        if(username.equals("admin")){
            permissions.add("*");//权限为所有
        }
        permissions.add("user:list");
        permissions.add("user:deleted");
        permissions.add("user:edit");
        return permissions;
    }

    //返回密文密码

    private String getEncPassword(String password,String salt){
        return new Md5Hash(password,salt,3).toString();
    }


    //private String getEncPassword(String password){
        //return new Md5Hash(password,null,3).toString();
    //}
}

②认证授权

public void testSaltMatcher(){
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        CustomRealm customRealm = new CustomRealm();
        //指定解密得方式
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        matcher.setHashAlgorithmName("md5");//md5加密
        matcher.setHashIterations(3);//加密得次数
        //配置到域中
        customRealm.setCredentialsMatcher(matcher);


        defaultWebSecurityManager.setRealm(customRealm);
        SecurityUtils.setSecurityManager(defaultWebSecurityManager);

        /*****************主体提交验证**************************/
        //获取主体
        Subject subject = SecurityUtils.getSubject();
        //创建主体提交时需要携带的token(由用户名密码组成)
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("test", "123456");

        try {
            //主体提交验证
            subject.login(usernamePasswordToken);
            /*****************主体提交验证**************************/
            //验证通过返回true,不通过返回false
            System.out.println("用户认证的状态" + subject.isAuthenticated());
            //判断该用户是否拥有这个角色
            subject.checkRoles("test");
            //校验是否拥有其权限
            subject.checkPermissions("user:deleted", "role:list");//是否拥有用户列表的权限
            //退出
            subject.logout();
            System.out.println("用户认证的状态" + subject.isAuthenticated());
        } catch (UnknownAccountException uae) {
            System.out.println("用户不存在");
        } catch (IncorrectCredentialsException ice) {
            System.out.println("用户名密码不匹配");
        } catch (LockedAccountException lae) {
            System.out.println("账号已经被锁定");
        } catch (AuthenticationException ae) {
            System.out.println("用户名密码不匹配");
        } catch (UnauthorizedException e) {
            System.out.println("该用户没有该权限访问");
        }
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值