Spring Boot 知识总结

news2024/11/24 6:21:38

Spring Boot 知识总结

一、Spring Boot基础

1.1 什么是Spring

Spring是一个开源框架,2003年兴起的一个Java轻量级开发框架,作者:Rod Johnson。

Spring是为了解决企业级应用开发的复杂性而创建的,简化开发。

Spring是如何简化Java开发的

为了降低Java开发的复杂性,Spring采用了以下4种关键策略:

  1. 基于POJO的轻量级和最小侵入性编程;
  2. 通过ICO,依赖注入(DI)和面向接口编程实现松耦合;
  3. 基于切面(AOP)和惯例进行声明式编程;
  4. 通过切面和模板减少样式代码

什么是SpringBoot

  1. Spring就是一个javaweb的开发框架,和SpringMVC类似,对比其他Javaweb的好处,官方说是简化开发,约定大于配置,you can “just run”,能迅速开发的web应用,几行代码开发一个http接口
  2. SpringBoot的主要优点:
    • 为所有Spring开发者更快速的入门
    • 开箱即用,提供各种默认配置来简化项目配置
    • 内嵌式容器简化Web项目
    • 没有冗余代码生成和XML配置的要求

1.2 微服务

微服务介绍

  1. 什么是微服务

    微服务是一种架构风格,它要求我们在开发应用的时候,这个应用必须构建成一系列小服务的组合;可以通过http的方式进行互通。

  2. 单体应用架构

    • 所谓单体应用架构(all in one)是指我们将一个应用中的所有应用服务都封装在一个应用服务中
    • 无论是CRM、ERP或是其他什么系统,你都把数据库访问、web访问等等各种功能都放到一个war包内
    • 这样做的好处是易于开发和测试,也十分方便部署;当需要拓展是,只需将war复制多份,然后放到多个服务器上,再做一个负载均衡就可以了
    • 单体架构的缺点是,哪怕我需要改一个非常小的地方,我都需要停掉整个服务,重新打包、部署这个应用war包。特别是对于一个大型项目,我们不可能把所有应用都放在一个应用里面,这样我们如何维护、如何分工合作都是问题

微服务架构

  1. all in one 架构方式,我把所有功能单元都放在一个应用里面,然后我们把整个应用都部署在服务器上。如果负载能力不行,我们把整个应用进行水平复制、进行拓展,然后再负载均衡
  2. 所谓微服务架构就是打破之前all in one的架构风格,把每个功能元素独立出来。把独立出来的功能元素动态组合,需要的功能元素才拿来组合,需要多一些时可以整合多个功能元素。所以微服务架构是对功能元素进行复制,而没有对整个应用进行复制
  3. 这样做的好处:
    • 节省了调用资源
    • 每个功能元素的服务都是一个可替换的、可独立升级的软件代码

如何构建微服务

  1. 一个大型系统的微服务架构,就像是一个复杂交织的神经网络,每一个神经元就是一个功能元素,它们各自完成自己的功能,然后通过http互相请求调用。比如一个电商系统,查缓存、查数据库、浏览页面、结账、支付等服务都是一个个独立的功能服务,都被微化了,它们作为一个个微服务共同构建了一个庞大的系统。如果修改其中的一个功能,只需要更新其中一个功能服务单元即可

  2. 但是这种庞大的架构给部署和运维带来了很大的难度。于是Spring为我们带来了构建大型分布式微服务的全套产品:

    • 构建一个个功能独立的微服务应用单元,可以使用SpringBoot,可以帮我们快速构建一个应用
    • 大型分布式网络服务的调用,这部分由SpringCloud来完成,实现分布式
    • 在分布式中间,进行流式数据计算、批处理,我们有SpringCloudDataFlow
    • Spring为我们想清楚了从开始构建应用到大型分布式应用的全流程方案
  3. 微服务:

    原文是 Martin Fowler 于 2014 年 3 月 25 日写的《Microservices》,翻译链接:

    https://www.kuangstudy.com/bbs/1374644434515275777

1.3 自动装配原理

  1. 自动配置:pom.xml

    spring-boot-dependencies:核心在父工程中
    
  2. 我们在写或者引入一些SpringBoot依赖的时候,不需要制定版本就是因为有这些版本仓库

  3. 启动器

    • 启动器:说白了,就是SpringBoot的使用场景
    • 比如说,spring-boot-starter-web,它就会自动帮我们导入web环境下所有的依赖
    • SpringBoot会将所有的功能场景,变成一个个的启动器
    • 我们要使用什么功能,只需要找到对应的启动器就可以了
    <!--启动器-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    
  4. 主程序

    • 代码

      //@SpringBootApplication:标注这个类是一个SpringBoot的应用
      @SpringBootApplication
      public class HelloApplication {
          //将SpringBoot应用启动
          public static void main(String[] args) {
              SpringApplication.run(HelloApplication.class, args);
          }
      
      }
      
    • 注解解析:

      @SpringBootConfiguration:SpringBoot的配置
         @Configuration:Spring配置类
         @Component:说明这也是一个Spring的组件
      
      @EnableAutoConfiguration:自动配置
         @AutoConfigurationPackage:自动配置包
             @Import({AutoConfigurationPackage.Registrar.class}):自动配置包注册
         @Import({AutoConfigurationImportSelector.class}) :自动配置导入选择器
         
      //获取所有的配置 
      List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
      
      //获取候选配置方法
      protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
              List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
              Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
              return configurations;
          }
          
      
  5. META-INF/spring.factories:自动配置的核心文件
    

image-20220321164257958

  1. 总结

    SpringBoot中所有的自动配置都在启动类中被扫描并加载,spring.factories:所有的自动配置类都在这里了,但不一定生效,要判断条件是否满足,只要导入了对应的start,就有对应的启动器了,有了启动器我们的自动装配就会生效,然后就配置成功了

    1)SpringBoot在启动的时候,从类路径下/META-INF/spring.factories获取指定的值

    2)将这些自动配置的类导入容器,自动配置就会生效,帮我们进行自动配置

    3)以前我们需要自动配置的东西,现在SpringBoot帮我们做了

    4)整个Java EE,解决方案和自动配置的东西都在spring-boot-autoconfigure-2.6.4.jar这个包下

    5)它会把所有需要导入的组件以类名方式返回,这些组件就会被添加到容器

    6)容器中也会存在很多的XXXAutoConfiguration的文件(@Bean:组件),就是这些类给容器中导入了这个场景所需要的所有组件;并自动配置,@Configuration(配置),javaConfig!

    7)有了自动配置类,就免去了我们手动编写配置文件的工作

  2. 关于SpringBoot谈谈你的理解:

    • 自动装配

    • run()

      1.推断应用的类型是普通的项目还是Web项目

      2.查找并加载所有可用初始化器,设置到initializers属性中

      3.找出所有的应用程序监听器,设置到listeners属性中

      4.推断并设置main方法的定义类,找到运行的主类

1.4 yaml语法详解

配置文件

SpringBoot使用一个全局的配置文件,配置文件名称是固定的

application.properties

○ 语法结构: key=value

# SpringBoot这个配置文件到底有哪些东西呢?
#
# 官方的配置太多了
#
# 了解原理:一通百通
# 将其删除,创建application.yaml文件,因为properties只能保存键值对
name=xiaoShu

student.name=xiaoShu
student.age=3

application.yml

○ 语法结构:key:空格 value

# k=v
#对空格的要求十分高!
#普通的key-value

# 可以注入到配置类中!

name: xiaoShu
# 对象
student:
  name: xiaoShu
  age: 3

# 行内写法
# student: {name: xiaoShu,age: 3}

# 数组
pets:
  - dog
  - cat
  - pig

# pets: [dog,cat,pig]

配置文件的作用∶修改SpringBoot自动配置的默认值,因为SpringBoot在底层都给我们自动配置好了;

YAML

YAML是"YAML Ain’t a Markup Language"(YAML不是一种置标语言)的递归缩写。

在开发的这种语言时,YAML的意思其实是:“Yet Another Markup Language”(仍是一种置标语言)

YAML A Markup Language:是一个标记语言

YAML is not Markup Language:不是一个标记语言

标记语言

以前的配置文件,大多数都是使用xml来配置;比如一个简单的端口配置,我们来对比下yaml和xml

yaml配置:

  • yaml可以直接给实体类赋值
server:
  port: 8080

xml配置:

<server>
<port>8080<server>
</server>

功能对比图:image-20220326155552179

  • cp只需要配置一次即可,@value()则需要每个字段都添加

  • 松散绑定:这个是什么意思呢?比如我的yaml中写的last-name,这个和lastName是一样的,-后面跟着的字母默认是大写的。这就是松散绑定。

  • JSR303数据校验:这个就是我们为字段增加一层过滤器验证,保证我们数据的合法性

    SpringBoot中可以使用@validated来校验数据,如果数据异常就会统一抛出异常,方便异常中心统一处理。这里我们来写个注解让我们的name只支持email格式

    @Component         //表示Spring的组件:实体类,注册Bean
    @ConfigurationProperties(prefix = "dog")
    @Validated         //数据校验
    public class Dog {
        //@Value("旺财")  //给属性赋值
        @Email //name必须是邮箱格式
        private String name;
        @Value("#{11*2}")    //#{SPEL} Spring表达式
        private Integer age;
    
  • 复杂类型封装:yaml可以支持封装数据对象,@value就不支持

结论:

  • 配置yaml和properties都可以获取到值,一般使用yaml
  • 如果我们在业务中,只需要获取配置文件中的某个值可以使用一下@value
  • 如果说,我们专门编写了一个JavaBean来和配置文件进行映射,就直接使用@ConfigurationProperties(prefix = “XXX”),不要犹豫!

SpringBoot的多环境配置,可以选择激活哪一个

application.properties配置:

image-20220326170543895

application.yaml配置:

image-20220326171131967

自动配置原理总结:

一句话总结:根据当前不同的条件判断,决定这个配置类是否生效
一旦这个配置类生效,这个配置类就会给容器中添加各种组件;这些组件的属性是从对应的properties类中获取的,这些类的
每一个属性又是和配置文件绑定的

这就是自动装配的原理!精髓:
1)、SpringBoot启动会加载大量的自动配置类
2)、我们看我们需要的功能有没有在SpringBoot默认写好的自动配置类当中;
3)、我们再来看这个自动配置类中到底配置了哪些组件;(只要我们要用的组件存在在其中,我们就不需要再手动配置了)
4)、给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们只需要在配置文件中指定这些属性的值即可;
xxxAutoConfigurartion:自动配置类;给容器中添加组件xxxxProperties:封装配置文件中相关属性;

#可以通过debug: true来查看哪些自动配置类生效了,哪些没有生效
debug: true

二、Spring Boot:Web开发

2.1 静态资源

(模板库:百度bootstarap模板)

public void addResourceHandlers(ResourceHandlerRegistry registry) {
    if (!this.resourceProperties.isAddMappings()) {
        //自定义路径返回
        logger.debug("Default resource handling disabled");
    } else {
         //系统默认路径返回
        if (!registry.hasMappingForPattern("/webjars/**")) {
            ResourceHandlerRegistration registration = registry.addResourceHandler(new String[]{"/webjars/**"}).addResourceLocations(new String[]{"classpath:/META-INF/resources/webjars/"});
            this.configureResourceCaching(registration);
            this.customizeResourceHandlerRegistration(registration);
        }

        String staticPathPattern = this.webFluxProperties.getStaticPathPattern();
        if (!registry.hasMappingForPattern(staticPathPattern)) {
            ResourceHandlerRegistration registration = registry.addResourceHandler(new String[]{staticPathPattern}).addResourceLocations(this.resourceProperties.getStaticLocations());
            this.configureResourceCaching(registration);
            this.customizeResourceHandlerRegistration(registration);
        }
    }
}

总结:

  1. 在springboot,我们可以使用以下方式处理静态资源(index.html放在这些路径下访问:http://localhost:8080/即可打开首页)
  • webjars localhost:8080/webjars/

  • public,static,/**,resources localhost:8080/

    注:优先级: resources>static (默认) >public

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WW1IU0WC-1672045313267)(C:\Users\kevin\AppData\Roaming\Typora\typora-user-images\image-20220326204600017.png)]

2.2 模板引擎ThymeLeaf

前端交给我们的页面,是html页面。如果是我们以前开发,我们需要把他们转成jsp页面,jsp好处就是当我们查出一些数据转发到JSP页面以后,我们可以用jsp轻松实现数据的显示,及交互等。jsp支持非常强大的功能,包括能写Java代码,但是呢,我们现在的这种情况,
SpringBoot这个项目首先是以jar的方式,不是war,像第二,我们用的还是嵌入式的Tomcat,所以呢,他现在默认是不支持jsp的。

那不支持jsp,如果我们直接用纯静态页面的方式,那给我们开发会带来非常大的麻烦,那怎办呢,SpringBoot推荐你可以来使用模板引擎

那么这模板引擎,我们其实大家听到很多,其实jsp就是一个模板引擎,还有以用的比较多的freemarker,包括SpringBoot给我们推荐的Thymeleaf,模板引擎有非常多,但再多的模板引擎,他们的思想都是一样的,什么样一个思想呢我们来看一下这张图。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BhPH2gNM-1672045313267)(C:\Users\kevin\AppData\Roaming\Typora\typora-user-images\image-20220326213219319.png)]

模板引擎的作用就是我们来写一个页面模板,比如有些值呢,是动态的,我们写一些表达式。而这些值,从哪来呢,我们来组装一些数据,我们把这些数据找到。然后把这个模板和这个数据交给我们模板引擎,模板引擎按照我们这个数据帮你把这表达式解析、填充到我们指定的立置,然后把这个数据最终生成一个我们想要的内容给我们写出去,这就是我们这个模板引擎,不管是jsp还是其他模板引擎,都是这个思想。只不过呢,就是说不同模板引擎之间,他们可能这个语法有点不一样。其他的我就不介绍了,我主要来介绍一下SpringBoot给我们推荐的Thymeleaf模板引擎,这模板引擎呢,是一个高级语言的模板引擎,他的这个语法更简单。而且呢,功能更强大。

  1. 导入ThymeLeaf依赖
 <!--ThymeLeaf依赖-->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
</dependency>
<dependency>
    <groupId>org.thymeleaf.extras</groupId>
    <artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>
  1. 测试

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1LpJprgE-1672045313267)(C:\Users\kevin\AppData\Roaming\Typora\typora-user-images\image-20220326214831662.png)]

结论:只要需要需要使用thymeleaf,导入对应的依赖就可以了;然后我们将html页面放在templates目录下即可

//index.html
<!--所有的html元素都可以被thymeLeaf 替换接管:th:元素名-->
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div th:text="${msg}"></div>
</body>
</html>

//test.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>test</title>
</head>
<body>
test
<div th:text="${msg1}"></div>
<div th:each="user : ${users}" th:text="${user}"></div>
</body>
</html>

快捷键:Ctrl+F 类内搜索

扩展IndexController编写:

package com.shu.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.Arrays;

@Controller
//在templates目录下的所有页面只能通过controller才能跳转
//这个需要模板引擎的支持  thymeleaf
public class IndexController {
    @RequestMapping("/index")
    public String index(Model model){
        model.addAttribute("msg","index");
        return "index";
    }
    @RequestMapping("/test")
    public String test(Model model){
        model.addAttribute("msg1","Hello,World!");
        model.addAttribute("users", Arrays.asList("xiao","Shu"));
        return "test";
    }
}

2.3 扩展SpringMVC

我们要做的就是编写一个@Configuration注解类,并且类型要为WebMvcConfigurer,还不能标注@EnableWebMvc注解;

我们去自己写一个,我们新建一个包叫config,写一个类MyMvcConfig;

package com.shu.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.Locale;

@Configuration  //使这个类变成配置类
//如果你想自定义一些定制化的功能,只需要写这个组件,将它交给SpringBoot,SpringBoot就会帮我们自动装配!
//需要实现WebMvcConfigurer接口
public class MyMvcConfig implements WebMvcConfigurer {
    //ViewResolver:实现了视图解析器的类我们就可以把它叫做视图解析器
    @Bean
    public ViewResolver MyViewResolver(){
        return new MyViewResolver();
    }
    public static class MyViewResolver implements ViewResolver{
        @Override
        public View resolveViewName(String viewName, Locale locale) throws Exception {
            return null;
        }
    }
}

使用扩展SpringMVC实现视图跳转功能

package com.shu.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

//如果我们要扩展一个SpringMVC,官方建议我们这样去做!
@Configuration  //使这个类变成配置类
public class MyMvcConfig implements WebMvcConfigurer {
    //视图跳转
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/xiaoshu").setViewName("/test");
    }
}

在springboot中,有非常多的xxxx Configuration帮助我们进行扩展配置,只要看见了这个东西,我们就要注意了!

2.4 员工管理系统小案例

  1. application.yml文件相关配置
#关闭默认图标
#spring.mvc.favicon.enabled=false
spring:
  mvc:
    favicon:
      enabled: false

#关闭模板引擎的缓存
#spring.thymeleaf.cache=false
  thymeleaf:
    cache: false
#自定义项目访问路径
server:
  servlet:
    context-path: /xiaoshu

2.页面国际化:

简写:

i18n ——>internationalization:首字母 + 尾字母 + 单词数量

例:k8s

总结:

1.首页配置

  • 注意点,所有页面的静态资源都需要使用thymeleaf接管
  • url: @{}
<a class="btn btn-sm" th:href="@{/index(l='zh_CN')}">中文</a>
<a class="btn btn-sm" th:href="@{/index(l='en_US')}">English</a>

2.页面国际化︰

  • 我们需要配置i18n文件
  • 我们如果需要在项目中进行按钮自动切换,我们需要自定义一个组件LocaleResolver
  • 记得将自己写的组件配置到spring容器@Bean
  • #{}
package com.shu.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

//如果我们要扩展一个SpringMVC,官方建议我们这样去做!
@Configuration  //使这个类变成配置类
public class MyMvcConfig implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("index");
        registry.addViewController("/index").setViewName("index");
    }
    //自定义的国际化组件就生效了!
    @Bean
    public LocaleResolver localeResolver(){
        return new MyLocaleResolver();
    }
}
package com.shu.config;


import org.springframework.util.StringUtils;
import org.springframework.web.servlet.LocaleResolver;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;

public class MyLocaleResolver implements LocaleResolver {
    //解析请求
    @Override
    public Locale resolveLocale(HttpServletRequest request) {
        //获取请求中的语言参数
        String language = request.getParameter("l");
        //如果没有就使用默认的
        Locale locale = Locale.getDefault();
        //如果请求的链接携带了国际化的参数
        if(!StringUtils.isEmpty(language)){
            //zh_CN
            String[] split = language.split("_");
            //国家、地区
            locale = new Locale(split[0],split[1]);
        }
        return locale;
    }

    @Override
    public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {

    }
}
  1. thymeleaf实现代码复用

    • dashboard.html

      <!--侧边栏   抽取公共部分:th:fragment="sidebar"-->
      <nav class="col-md-2 d-none d-md-block bg-light sidebar" th:fragment="sidebar"></>
      
    • list.html

      <!--侧边栏-->
      <div th:insert="~{dashboard :: sidebar}"></div>
      
      <!--侧边栏-->
      <div th:replace="~{commons/commons.html :: sidebar(active='list.html')}"></div>
      
  2. 员工列表展示

    • 提取公共页面

    • th:fragment=“sidebar”

    • th:replace=“~{commons/commons : :topbar}”

    • 如果要传递参数,可以直接使用()传参,接收判断即可!2.列表循环展示

  3. 添加员工

    1. 按钮提交
    2. 跳转到添加页面
    3. 添加员工成功
    4. 返回首页
  4. CRUD

  5. 404

三、Spring Data

3.1简介

对于数据访问层,无论是 SQL(关系型数据库)还是 NOSQL(非关系型数据库),Spring Boot 底层都是采用Spring Data 的方式进行统一处理。
Spring Boot 底层都是采用 Spring Data 的方式进行统一处理各种数据库,Spring Data 也是 Spring 中与 Spring Boot、Spring Cloud 等齐名的知名项目。
Sping Data 官网: https://spring.io/projects/spring-data

数据库相关的启动器:

可以参考官方文档: https://docs.spring.io/spring-boot/docs/2.1.7.RELEASE/reference/htmlsingle/#using-boot-starter

3.2 JDBC

准备工作

  1. 我们去新建一个项目测试: Springboot_Data ;引入相应的模块! 基础模块

image-20221209143433127

  1. 添加相关依赖

image-20221209143719206

  1. 配置数据库参数

    spring:
      datasource:
        username: root
        password: 123456
        # 假如时区报错了,就增加一个时区的配置就行:serverTimeone=UTC
        url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8&serverTimeone=UTC
        driver-class-name: com.mysql.jdbc.Driver
    

image-20221209145244134

  1. 数据库创建
CREATE DATABASE if NOT EXISTS `mybatis`;
USE `mybatis`;
CREATE TABLE `user`(
  `id` INT(10) NOT NULL COMMENT '用户id',
	`name` VARCHAR(50) NOT NULL COMMENT '用户名',
	`pwd` VARCHAR(50) NOT NULL COMMENT '密码',
	PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO `user`(`id`,`name`,`pwd`) 
VALUES(1,'张三','123456'),
(2,'李四','123456'),
(3,'王五','123456');
  1. 测试连接
package com.shu;

import jakarta.annotation.Resource;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

@SpringBootTest
class SpringbootDataApplicationTests {
    //自动装配包括@Autowired,@Resource,注意此处不能使用@Autowired进行自动装配
    //@Autowired是按类型查找Bean,@Resource是按名查找Bean
    //yaml配置文件应该不支持使用@Autowired进行自动装配,如果此处使用@Autowired就会报错
    @Resource
    DataSource dataSource;
    @Test
    void contextLoads() {
        System.out.println();
        //查看默认的数据源  class com.zaxxer.hikari.HikariDataSource:dbcp,Springboot默认的数据源
        System.out.println(dataSource.getClass());

        //获得数据库连接
        try {
            Connection connection = dataSource.getConnection();
            System.out.println(connection);

            //xxx Template:Springboot已经配置好模板bean,拿来即用;下面用一下jdbc Template给大家看一下
            //jdbc Template
            //redis Template

            connection.close();
        } catch (Exception ex) {
            ex.printStackTrace();
        }

    }

}
  1. 连接成功

image-20221216145845340

jdbc增删改查

  1. 新建一个controller

    package com.shu.controller;
    
    import jakarta.annotation.Resource;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.List;
    import java.util.Map;
    
    @RestController
    public class JdbcController {
        @Resource
        JdbcTemplate jdbcTemplate;
        //查询数据库的所有信息并显示到网页
        //没有实体类,数据库中的东西怎么获取? Map
        @GetMapping("/queryUser")
        public List<Map<String,Object>> userList(){
            String sql = "SELECT * FROM `user`";
            List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql);
            return maps;
        }
        @GetMapping("/addUser")
        public String addUser(){
            String sql = "INSERT `user`(name,pwd) VALUES('新区','122456')";
            //jdbcTemplate.execute(sql);
            jdbcTemplate.update(sql);
            return "新增成功";
        }
        @GetMapping("/updateUser/{id}")
        public String updateUser(@PathVariable("id") int id){
            String sql = "UPDATE `user` SET `name`=?,pwd=? WHERE id="+id;
            //jdbcTemplate.execute(sql);
            Object[] objects = new Object[2];
            objects[0]="xxx";
            objects[1]="123456";
    
            jdbcTemplate.update(sql,objects);
            return "更新成功";
        }
        @GetMapping("/deleteUser/{id}")
        public String deleteUser(@PathVariable("id") int id){
            String sql = "DELETE FROM `user` WHERE id = ?";
            //jdbcTemplate.execute(sql);
            jdbcTemplate.update(sql,id);
            return "删除成功";
        }
    }
    
  2. 注意,使用@RestController注解需要引入一个在pom.xm文件中引入一个web依赖

    <!--web依赖-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
  3. 查询成功,其他就不一一测了

    image-20221216152725760

3.3 整合Druid数据源

Druid是阿里巴巴开源平台上一个数据库连接池实现,结合了C3PO、DBCP、PROXOOL等DB池的优点,同时加入了日志监控。

Druid可以很好的监控DB池连接和SQL的执行情况,天生就是针对监控而生的DB 连接池。
Spring Boot 2.0以上默认使用Hikari 数据源,接下是我们使用Spring Boot集成Druid数据源,实现数据库监控。

  1. 第一步需要在应用的 pom.xml 文件中添加上 Druid 数据源依赖,而这个依赖可以从 Maven 仓库官网中获取

Maven Repository :https://mavenrepository.com/

<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.15</version>
</dependency>
  1. 导入上面的依赖到我们的项目中

  2. 在配置文件中指定使用的数据源为druid,并测试查看:

image-20221216163019652

  1. druid数据源配置
spring:
  datasource:
    username: root
    password: 123456
    # 假如时区报错了,就增加一个时区的配置就行:serverTimeone=UTC
    url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8&serverTimeone=UTC
    driver-class-name: com.mysql.cj.jdbc.Driver
    # 通过type属性切换数据源:使用druid数据源
    type: com.alibaba.druid.pool.DruidDataSource
    
    #Spring Boot 默认是不注入这些属性值的,需要自己绑定
    #druid 数据源专有配置
    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true

    #配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
    #如果允许时报错  java.lang.ClassNotFoundException: org.apache.log4j.Priority
    #则导入 log4j 依赖即可,Maven 地址:https://mvnrepository.com/artifact/log4j/log4j
    filters: stat,wall,log4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

5.导入log4j依赖

<!--log4j-->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.12</version>
</dependency>

6.编写控制器

package com.shu.config;


import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import jakarta.servlet.Servlet;
import jakarta.servlet.http.HttpServlet;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.util.HashMap;

@Configuration
public class DruidConfig {

    //将druid数据源及其配置参数注册到容器
    @ConfigurationProperties(prefix = "spring.datasource")  //与yaml文件进行绑定
    @Bean
    public DataSource druidDataSource(){
        return new DruidDataSource();
    }
    /*//后台监控:web.xml   此处有问题,未能解决
    @Bean
    public ServletRegistrationBean statViewServlet(){
        ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");

        //后台需要有人登录,账号密码配置
        HashMap<String, String> initParameters = new HashMap<>();

        //增加配置
        initParameters.put("loginUsername","admin");//key固定
        initParameters.put("loginPassword","123456");

        //允许谁可以访问
        initParameters.put("allow","");//第二个参数表示可以允许的用户,不填表示都可以访问
        //禁止谁能访问   initParameters.put("","","");参数表示禁止的用户

        //设置初始化参数
        bean.setInitParameters(initParameters);
        return bean;
    }*/
}

3.4 整合mybatis

  1. 导入mybatis依赖

    <!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>3.0.0</version>
    </dependency>
    
  2. 导入lombok依赖

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    
  3. 新建User类

    package com.shu.entity;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import org.springframework.beans.factory.annotation.Autowired;
    @Data
    @NoArgsConstructor //无参构造
    @AllArgsConstructor //有参构造
    public class User {
        private int id;
        private String name;
        private String pwd;
    }
    
  4. 新建UserMapper类

    package com.shu.mapper;
    
    import com.shu.entity.User;
    import org.apache.ibatis.annotations.Mapper;
    import org.springframework.stereotype.Repository;
    
    import java.util.List;
    
    @Mapper  //这个注解表示了这是一个mybtis的mapper类,另外一种实现:在启动类上加,@MapperScan("com.shu.mapper")
    @Repository  //mapper是属于DAO层,所以需要这个注解
    public interface UserMapper {
        //扩展知识,接口中的属性:
        /*
        在interface里面的变量默认都是public static final 的。所以可以直接省略修饰符,编译时编译器会自动加上:
        String param = "xiaoshu";//变量需要初始化
        */
        int age = 18;  // 即:public static final int age = 18;
    
        List<User> queryUserList();
        User queryUserById(int id);
        void addUser(User user);
        void updateUser(User user);
        void deleteUser(int id);
    }
    
  5. 配置UserMapper.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.shu.mapper.UserMapper">
        <!--id,resultType要生效,需要在yaml配置文件中设置相关配置,否则不会生效-->
        <select id="queryUserList" resultType="User">
          select * from user
        </select>
        <select id="queryUserById" resultType="User">
            select * from user where id=#{id}
        </select>
        <insert id="addUser" parameterType="User">
             insert into user(name,pwd) values (#{name},#{pwd})
        </insert>
        <update id="updateUser" parameterType="User">
            update user set name =#{name},pwd=#{pwd} where id = #{id}
        </update>
        <delete id="deleteUser" parameterType="User">
            delete from user where id=#{id}
        </delete>
    </mapper>
    
  6. 新增yaml中的mybatis配置

    #spring 配置
    spring:
      datasource:
        username: root
        password: 123456
        # 假如时区报错了,就增加一个时区的配置就行:serverTimeone=UTC
        url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8&serverTimeone=UTC
        driver-class-name: com.mysql.cj.jdbc.Driver
        # 通过type属性切换数据源:使用druid数据源
        type: com.alibaba.druid.pool.DruidDataSource
    
        #Spring Boot 默认是不注入这些属性值的,需要自己绑定
        #druid 数据源专有配置
        initialSize: 5
        minIdle: 5
        maxActive: 20
        maxWait: 60000
        timeBetweenEvictionRunsMillis: 60000
        minEvictableIdleTimeMillis: 300000
        validationQuery: SELECT 1 FROM DUAL
        testWhileIdle: true
        testOnBorrow: false
        testOnReturn: false
        poolPreparedStatements: true
    
        #配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
        #如果允许时报错  java.lang.ClassNotFoundException: org.apache.log4j.Priority
        #则导入 log4j 依赖即可,Maven 地址:https://mvnrepository.com/artifact/log4j/log4j
        filters: stat,wall,log4j
        maxPoolPreparedStatementPerConnectionSize: 20
        useGlobalDataSourceStat: true
        connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
    
    #整合mybatis,需要在这里配置,否则xml不会生效
    mybatis:
      type-aliases-package: com.shu.entity
      mapper-locations: classpath:mybatis/mapper/*.xml
    
  7. 编写controller

    package com.shu.controller;
    
    import com.shu.entity.User;
    import com.shu.mapper.UserMapper;
    import org.springframework.beans.factory.annotation.Autowired;
    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.RestController;
    
    import java.util.List;
    
    @RestController
    public class UserController {
        @Autowired
        private UserMapper userMapper;
    
        @GetMapping("/queryUserList")
        public List<User> queryUserList(){
            List<User> users = userMapper.queryUserList();
            for (User user: users) {
                System.out.println(user);
            }
            return users;
        }
        @GetMapping("/queryUserById/{id}")
        public User queryUserById(@PathVariable int id){
            User user = userMapper.queryUserById(id);
            return user;
        }
        @GetMapping("/addUsers")
        public String addUser(){
            userMapper.addUser(new User(6,"小雨","123456"));
            return "新增成功";
        }
        @GetMapping("/updateUsers")
        public String updateUsers(){
            userMapper.updateUser(new User(14,"小雨","666666"));
            return "修改成功";
        }
        @GetMapping("/deleteUsers/{id}")
        public String deleteUser(@PathVariable int id){
            userMapper.deleteUser(id);
            return "删除成功";
        }
    }
    
  8. 自己去测试即可

四、Security:安全

在web开发中,安全是第一位!过滤器,拦截器~

功能性需求:否

做网站:安全应该在什么时候考虑?设计之初!

  • 漏洞,用户隐私泄漏
  • 架构一旦确定,代码也写完了再去写安全,会改动大量代码

市面上知名的安全框架:shiro(主要学习这一种)、SpringSecurity,它们很像,除了类不一样,名字不一样

  • 认证
  • 授权(vip1,vip2,vip3)

权限:

  • 功能权限
  • 访问权限
  • 菜单权限
  • 拦截器、过滤器:大量的原生代码~冗余

AOP:横切~ 配置类

4.1 SpringSecurity简介(了解)

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

<!--导入security依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

记住几个类:

  • WebSecurityConfigurerAdapter: 自定义Security策略(已弃用,暂时不做学习了,这里只是提一下)

  • AuthenticationManagerBuilder: 自定义认证策略

  • @EnableWebSecurity: 开启WebSecurity模式 @Enablexxx 开启某个功能

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

  • 认证(Authentication)

  • 授权(Authorization)

这个概念是通用的,而不是只在Spring Security 中存在
参考官网: https://spring.io/projects/spring-security ,查看我们自己项目中的版本,找到对应的帮助文档

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

4.2 Shiro简介(重点掌握)

4.2.1 什么是Shiro?

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

image-20221219173002708

4.2.2 有哪些功能?

image-20221219180038979

  • Authentication: 身份认证、登录,验证用户是不是拥有相应的身份;
  • Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限,即判断用户能否进行什么提作,如:验证某个用户是否拥有某个角色,或者细粒度的验证某个用户对某个资源是否具有某个权限!Session Manager: 会话管理,即用户登录后就是第一次会话,在没有退出之前,它的所有信息都在会话中:会话可以是普通的JavaSE环境,也可以是Web环境;
  • Cryptography:加密,保护数据的安全性,如密码加密存储到数据库中,而不是明文存储。Web Support: Web支持,可以非常容易的集成到Web环境;
  • Caching:缓存,比如用户登录后,其用户信息,拥有的角色、权限不必每次去查,这样可以提高效率
  • Concurrency:Shiro支持多线程应用的并发验证,即,如在一个线程中开启另一个线程,能把权限自动的传播过去
  • Testing:提供测试支持;
  • Run As:允许一个用户假装为另一个用户 (如果他们允许)的身份进行访问;
  • Remember Me:记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了

4.2.3 Shiro架构 (外部)

从外部来看Shiro,即从应用程序角度来观察如何使用shiro完成工作:

image-20221219180246913

  • subject: 应用代码直接交互的对象是Subiect,也就是说Shiro的对外AP核心就是Subiect,Subiect代表了当前的用户,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是Subiect,如网络爬虫,机器人等,与Subject的所有交互都会委托给SecurityManager; Subject其实是一个门面,SecurityManageer 才是实际的执行者
  • SecurityManager: 安全管理器,即所有与安全有关的操作都会与SercurityManager交互,并且它管理着所有的Subject,可以看出它是shiro的核心,它负责与Shiro的其他组件进行交互,它相当于SpringMVC的DispatcherServlet的角色
  • Realm: Shiro从Realm获取安全数据 (如用户,角色,权限),就是说SecurityManager 要验证用户身份那么它需要从Realm 获取相应的用户进行比较,来确定用户的身份是否合法; 也需要从Realm得到用户相应的角色、权限,进行验证用户的操作是否能够进行,可以把Realm看成DataSource

4.2.4 Shiro架构(内部)

image-20221220102602398

  • Subiect: 任何可以与应用交互的“用户’.
  • Security Manager: 相当于SpringMVC中的DispatcherServlet; 是shiro的心脏,所有具体的交互都通过Security Manager进行控制,它管理者所有的Subject,且负责进行认证,授权,会话,及缓存的管理。
  • Authenticator: 负责Subiect认证,是一个扩展点,可以自定义实现,可以使用认证策略 (AuthenticationStrategy),即什么情况下算用户认证通过了;
  • Authorizer: 授权器,即访问控制器,用来决定主体是否有权限进行相应的操作;即控制着用户能访问应用中的那些功能;
  • Realm: 可以有一个或者多个的realm,可以认为是安全实体数据源,即用于获取安全实体的,可以用JDBC实.现,也可以是内存实现等等,由用户提供;所以一般在应用中都需要实现自己的realm
  • SessionManager: 管理Session生命周期的组件,而Shiro并不仅仅可以用在Web环境,也可以用在普通的JavaSE环境中
  • CacheManager: 缓存控制器,来管理如用户,角色,权限等缓存的;因为这些数据基本上很少改变,放到缓存中后可以提高访问的性能;
  • Cryptography: 密码模块,Shiro 提高了一些常见的加密组件用于密码加密,解密等

4.2.5 HelloWorld

快速实践

查看官网文档: http://shiro.apache.org/tutorial.html
官方的quickstart: https://github.com/apache/shiro/tree/master/samples/quickstart/

  1. 创建一个maven父工程:SpringBoot_Shiro,用于学习Shiro,删掉不必要的东西
  2. 创建一个普通的Maven子工程: Hello_Shiro
  3. 根据官方文档,我们来导入shiro的依赖
<dependencies>
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-core</artifactId>
        <version>1.10.1</version>
    </dependency>
    <!-- Shiro uses SLF4J for logging.  We'll use the 'simple' binding
         in this example app.  See http://www.slf4j.org for more info. -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-simple</artifactId>
        <version>1.7.21</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>jcl-over-slf4j</artifactId>
        <version>1.7.21</version>
    </dependency>
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.2</version>
    </dependency>
</dependencies>
  1. 新建log4j2.xml文件
<!--
  ~ Licensed to the Apache Software Foundation (ASF) under one
  ~ or more contributor license agreements.  See the NOTICE file
  ~ distributed with this work for additional information
  ~ regarding copyright ownership.  The ASF licenses this file
  ~ to you under the Apache License, Version 2.0 (the
  ~ "License"); you may not use this file except in compliance
  ~ with the License.  You may obtain a copy of the License at
  ~
  ~     http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing,
  ~ software distributed under the License is distributed on an
  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  ~ KIND, either express or implied.  See the License for the
  ~ specific language governing permissions and limitations
  ~ under the License.
  -->

<Configuration name="ConfigTest" status="ERROR" monitorInterval="5">
    <!--
      ~ Licensed to the Apache Software Foundation (ASF) under one
      ~ or more contributor license agreements.  See the NOTICE file
      ~ distributed with this work for additional information
      ~ regarding copyright ownership.  The ASF licenses this file
      ~ to you under the Apache License, Version 2.0 (the
      ~ "License"); you may not use this file except in compliance
      ~ with the License.  You may obtain a copy of the License at
      ~
      ~     http://www.apache.org/licenses/LICENSE-2.0
      ~
      ~ Unless required by applicable law or agreed to in writing,
      ~ software distributed under the License is distributed on an
      ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
      ~ KIND, either express or implied.  See the License for the
      ~ specific language governing permissions and limitations
      ~ under the License.
      -->

    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
    </Appenders>
    <Loggers>
        <Logger name="org.springframework" level="warn" additivity="false">
            <AppenderRef ref="Console"/>
        </Logger>
        <Logger name="org.apache" level="warn" additivity="false">
            <AppenderRef ref="Console"/>
        </Logger>
        <Logger name="net.sf.ehcache" level="warn" additivity="false">
            <AppenderRef ref="Console"/>
        </Logger>
        <Logger name="org.apache.shiro.util.ThreadContext" level="warn" additivity="false">
            <AppenderRef ref="Console"/>
        </Logger>
        <Root level="info">
            <AppenderRef ref="Console"/>
        </Root>
    </Loggers>
</Configuration>
  1. 新建shiro.ini文件
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
#
# =============================================================================
# Quickstart INI Realm configuration
#
# For those that might not understand the references in this file, the
# definitions are all based on the classic Mel Brooks' film "Spaceballs". ;)
# =============================================================================

# -----------------------------------------------------------------------------
# Users and their assigned roles
#
# Each line conforms to the format defined in the
# org.apache.shiro.realm.text.TextConfigurationRealm#setUserDefinitions JavaDoc
# -----------------------------------------------------------------------------
[users]
# user 'root' with password 'secret' and the 'admin' role
root = secret, admin
# user 'guest' with the password 'guest' and the 'guest' role
guest = guest, guest
# user 'presidentskroob' with password '12345' ("That's the same combination on
# my luggage!!!" ;)), and role 'president'
presidentskroob = 12345, president
# user 'darkhelmet' with password 'ludicrousspeed' and roles 'darklord' and 'schwartz'
darkhelmet = ludicrousspeed, darklord, schwartz
# user 'lonestarr' with password 'vespa' and roles 'goodguy' and 'schwartz'
lonestarr = vespa, goodguy, schwartz

# -----------------------------------------------------------------------------
# Roles with assigned permissions
# 
# Each line conforms to the format defined in the
# org.apache.shiro.realm.text.TextConfigurationRealm#setRoleDefinitions JavaDoc
# -----------------------------------------------------------------------------
[roles]
# 'admin' role has all permissions, indicated by the wildcard '*'
admin = *
# The 'schwartz' role can do anything (*) with any lightsaber:
schwartz = lightsaber:*
# The 'goodguy' role is allowed to 'drive' (action) the winnebago (type) with
# license plate 'eagle5' (instance specific id)
goodguy = winnebago:drive:eagle5
  1. 新建Quickstart启动类

    /*
     * Licensed to the Apache Software Foundation (ASF) under one
     * or more contributor license agreements.  See the NOTICE file
     * distributed with this work for additional information
     * regarding copyright ownership.  The ASF licenses this file
     * to you under the Apache License, Version 2.0 (the
     * "License"); you may not use this file except in compliance
     * with the License.  You may obtain a copy of the License at
     *
     *     http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing,
     * software distributed under the License is distributed on an
     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
     * KIND, either express or implied.  See the License for the
     * specific language governing permissions and limitations
     * under the License.
     */
    
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.*;
    import org.apache.shiro.mgt.DefaultSecurityManager;
    import org.apache.shiro.mgt.SecurityManager;
    import org.apache.shiro.realm.text.IniRealm;
    import org.apache.shiro.session.Session;
    import org.apache.shiro.subject.Subject;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    
    /**
     * Simple Quickstart application showing how to use Shiro's API.
     *
     * @since 0.9 RC2
     */
    public class Quickstart {
    
        private static final transient Logger log = LoggerFactory.getLogger(Quickstart.class);
    
    
        public static void main(String[] args) {
    
            // The easiest way to create a Shiro SecurityManager with configured
            // realms, users, roles and permissions is to use the simple INI config.
            // We'll do that by using a factory that can ingest a .ini file and
            // return a SecurityManager instance:
    
            // Use the shiro.ini file at the root of the classpath
            // (file: and url: prefixes load from files and urls respectively):
            //官方初始化加载方法已经过时了,新方法:初始化加载shiro.ini配置文件
            DefaultSecurityManager securityManager = new DefaultSecurityManager();
            IniRealm iniRealm = new IniRealm("classpath:shiro.ini");
            securityManager.setRealm(iniRealm);
    
            // for this simple example quickstart, make the SecurityManager
            // accessible as a JVM singleton.  Most applications wouldn't do this
            // and instead rely on their container configuration or web.xml for
            // webapps.  That is outside the scope of this simple quickstart, so
            // we'll just do the bare minimum so you can continue to get a feel
            // for things.
            SecurityUtils.setSecurityManager(securityManager);
    
            // Now that a simple Shiro environment is set up, let's see what you can do:
    
            // get the currently executing user:
            //获取当前的用户对象,currentUser:Subject
            Subject currentUser = SecurityUtils.getSubject();
    
            // Do some stuff with a Session (no need for a web or EJB container!!!)
            //通过当前用户拿到Session
            Session session = currentUser.getSession();
            session.setAttribute("someKey", "aValue");
            String value = (String) session.getAttribute("someKey");
            if (value.equals("aValue")) {
                log.info("Subject=>session [" + value + "]");
            }
    
            // let's login the current user so we can check against roles and permissions:
            //判断当前用户是否被认证
            if (!currentUser.isAuthenticated()) {
                //token:令牌,没有获取,随机
                UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
                token.setRememberMe(true);  //设置记住我
                try {
                    currentUser.login(token);  //执行了登录操作
                } catch (UnknownAccountException uae) {
                    log.info("There is no user with username of " + token.getPrincipal());
                } catch (IncorrectCredentialsException ice) {
                    log.info("Password for account " + token.getPrincipal() + " was incorrect!");
                } catch (LockedAccountException lae) {
                    log.info("The account for username " + token.getPrincipal() + " is locked.  " +
                            "Please contact your administrator to unlock it.");
                }
                // ... catch more exceptions here (maybe custom ones specific to your application?
                catch (AuthenticationException ae) {
                    //unexpected condition?  error?
                }
            }
    
            //say who they are:
            //print their identifying principal (in this case, a username):
            log.info("User [" + currentUser.getPrincipal() + "] logged in successfully.");
    
            //test a role:
            if (currentUser.hasRole("schwartz")) {
                log.info("May the Schwartz be with you!");
            } else {
                log.info("Hello, mere mortal.");
            }
            //粗粒度
            //test a typed permission (not instance-level)
            if (currentUser.isPermitted("lightsaber:wield")) {
                log.info("You may use a lightsaber ring.  Use it wisely.");
            } else {
                log.info("Sorry, lightsaber rings are for schwartz masters only.");
            }
            //细粒度
            //a (very powerful) Instance Level permission:
            if (currentUser.isPermitted("winnebago:drive:eagle5")) {
                log.info("You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'.  " +
                        "Here are the keys - have fun!");
            } else {
                log.info("Sorry, you aren't allowed to drive the 'eagle5' winnebago!");
            }
            //注销
            //all done - log out!
            currentUser.logout();
            //结束
            System.exit(0);
        }
    }
    
  2. 启动项目,出现红色部分的日志信息说明启动成功

    image-20221220160251497

4.2.6 SpringBoot中集成

  1. 导入Shiro依赖,项目用到的其他依赖也放进去了(需要自取)

    <dependencies>
        <!--
        Shiro核心三大对象:
        1、Subject: 用户
        2、SecurityManager:管理所有用户
        3、Realm:连接数据
        -->
        <!--导入shiro整合spring的包:shiro-spring-->
        <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.10.1</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>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
        </dependency>
    
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </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>
    
  2. 新建config包

    • ShiroConfig类

      package com.shu.config;
      
      import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
      import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
      import org.springframework.beans.factory.annotation.Qualifier;
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      
      @Configuration
      public class ShiroConfig {
          //ShiroFilterFactoryBean 第三步
          @Bean
          public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){
              ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
              //设置安全管理器
              shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
      
              return  shiroFilterFactoryBean;
          }
      
          //DefaultWebSecurityManager
          @Bean(name = "securityManager") //第二步
          //@Qualifier("userRealm"):与自己创建的 realm 对象进行绑定
          public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
              DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
      
              //关联UserRealm
              defaultWebSecurityManager.setRealm(userRealm);
      
              return defaultWebSecurityManager;
          }
      
          //创建 realm 对象,需要自定义
          //@Bean(name = "userRealm") //注册自定义的Bean,给spring进行托管,加上name属性也可以
          @Bean //第一步:注册自定义的Bean,给spring进行托管,不加也行
          public UserRealm userRealm(){
              return new UserRealm();
          }
      }
      
    • UserRealm类

      package com.shu.config;
      
      import org.apache.shiro.authc.AuthenticationException;
      import org.apache.shiro.authc.AuthenticationInfo;
      import org.apache.shiro.authc.AuthenticationToken;
      import org.apache.shiro.authz.AuthorizationInfo;
      import org.apache.shiro.realm.AuthorizingRealm;
      import org.apache.shiro.subject.PrincipalCollection;
      
      //自定义的 UserRealm,需要 extends AuthorizingRealm
      public class UserRealm extends AuthorizingRealm {
          //授权
          @Override
          protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
              System.out.println("执行了=>授权doGetAuthorizationInfo");
              return null;
          }
          //认证
          @Override
          protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
              System.out.println("执行了=>认证doGetAuthenticationInfo");
              return null;
          }
      }
      
  3. 在templates文件夹下新建index.html

    image-20221222101630032

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <h1>首页</h1>
    <p th:text="${msg}"></p>
    <p>Hello,Shiro</p>
    <hr/>
    <a th:href="@{/user/add}">add</a> | <a th:href="@{/user/update}">update</a>
    </body>
    </html>
    
  4. 在templates文件夹下新建user文件夹

    • add.html

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>Title</title>
      </head>
      <body>
      <h1>add</h1>
      </body>
      </html>
      
    • update.html

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>Title</title>
      </head>
      <body>
      <h1>update</h1>
      </body>
      </html>
      
  5. 新建MyController路由跳转页面

    package com.shu.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @Controller
    public class MyController {
        @RequestMapping({"/","/index"})
        public String toIndex(Model model){
            model.addAttribute("msg","hello,xiaoshu");
            return "index";
        }
        @RequestMapping("/user/add")
        public String add(){
            return "user/add";
        }
        @RequestMapping("/user/update")
        public String update(){
            return "user/update";
        }
    }
    
  6. 启动项目看能否正常启动,点击链接看能否正常跳转(我的是可以的)

    image-20221222102010953

报错解决

如果报下面这个错

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v3.0.0)

2022-12-22T10:00:57.345+08:00  INFO 22008 --- [           main] c.shu.SpringBootShiroStudyApplication    : Starting SpringBootShiroStudyApplication using Java 17.0.5 with PID 22008 (D:\Spring Boot\SpringBoot_Shiro\SpringBoot_ShiroStudy\target\classes started by 上官剑南 in D:\Spring Boot\SpringBoot_Shiro)
2022-12-22T10:00:57.351+08:00  INFO 22008 --- [           main] c.shu.SpringBootShiroStudyApplication    : No active profile set, falling back to 1 default profile: "default"
2022-12-22T10:00:57.794+08:00 ERROR 22008 --- [           main] o.s.boot.SpringApplication               : Application run failed

java.lang.NoClassDefFoundError: javax/servlet/Filter
	at java.base/java.lang.ClassLoader.defineClass1(Native Method) ~[na:na]
	at java.base/java.lang.ClassLoader._jr$defineClass(ClassLoader.java:1012) ~[na:na]
    ...
	... 83 common frames omitted

Exception in thread "main" java.lang.NoClassDefFoundError: javax/servlet/Filter
	at java.base/java.lang.ClassLoader.defineClass1(Native Method)
	at java.base/java.lang.ClassLoader._jr$defineClass(ClassLoader.java:1012)
	at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:43016)
	...
	at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
	... 71 more
与目标 VM 断开连接, 地址为: ''127.0.0.1:57537',传输: '套接字''

进程已结束,退出代码为 1

导入依赖即可

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
</dependency>

正常启动

image-20221222100410998

4.2.7 模板网站

  • layui:有免费有付费(需要自取)

  • my-site

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

    • 后台登录页面:http://localhost:8080/admin/login

      账号名:admin

      密码:123456

五、Swagger

前后端分离时代:

  • 后端:后端控制层,服务层,数据访问层【后端团队】
  • 前端:前端控制层,视图层【前端团队】
    • 伪造后端数据,json。已经存在了,不需要后端,前端工程依旧能够跑起来
  • 前后端如何交互?=>API接口
  • 前后端相对独立,松耦合
  • 前后端甚至可以部署在不同的服务器上

产生一个问题:

  • 前后端集成联调,前端人员和后端人员无法做到及时协商,尽早解决,最终导致问题集中爆发

解决方案:

  • 首先制定一个schema[计划的提纲],实时更新最新API,降低集成风险
  • 早些年:制定word计划文档
  • 前后端分离:
    • 前端测试后端接口:PostMan
    • 后端提供接口,需要实时更新最新的消息及时改动!

5.1 Swagger简介

  • 号称世界上最流行的Api框架
  • Restful Api 文档在线自动生成工具=>Api文档与Api定义同步更新
  • 直接运行,可以在线测试Api接口
  • 支持多种语言(java,php,C#…)
  • 官网:https://swagger.io/

在项目中使用Swagger需要springfox jar包

  • springfox-swagger2

    <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger2</artifactId>
        <version>3.0.0</version>
    </dependency>
    
  • ui

    <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger-ui</artifactId>
        <version>3.0.0</version>
    </dependency>
    

5.2 SpringBoot集成Swagger

  1. 新建一个SpringBoot_Swagger项目,需要勾选Spring Web

    image-20221222142746768

  2. 导入jar包

    <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger2</artifactId>
        <version>3.0.0</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger-ui</artifactId>
        <version>3.0.0</version>
    </dependency>
    
  3. 编写一个Hello工程

    package com.shu.controller;
    
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class HelloController {
         //项目请求分析:除了下面这个请求地址,还有一个默认的 /error页面
        @RequestMapping(value = "/hello")
        public String hello(){
            return "hello";
        }
    }
    
  4. 配置Swagger=>config

    package com.shu.config;
    
    import org.springframework.context.annotation.Configuration;
    import springfox.documentation.swagger2.annotations.EnableSwagger2;
    
    @Configuration //等价于:@Component,只要加了这个注解就会把它自动配置到spring的配置里面
    @EnableSwagger2 //开启Swagger2
    public class SwaggerConfig {
    
    }
    
  5. 测试运行

报错一

java.lang.TypeNotPresentException: Type javax.servlet.http.HttpServletRequest not present
	at java.base/sun.reflect.generics.factory.CoreReflectionFactory.makeNamedType(CoreReflectionFactory.java:117) ~[na:na]
	at java.base/sun.reflect.generics.visitor.Reifier.visitClassTypeSignature(Reifier.java:125) ~[na:na]
	at java.base/sun.reflect.generics.tree.ClassTypeSignature.accept(ClassTypeSignature.java:49) ~[na:na]
	...
	at java.base/java.lang.Class.forName(Class.java:467) ~[na:na]
	at java.base/sun.reflect.generics.factory.CoreReflectionFactory.makeNamedType(CoreReflectionFactory.java:114) ~[na:na]
	... 34 common frames omitted

报错一解决:导入以下依赖

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
</dependency>

报错2 原因

这是因为Springfox使用的路径匹配是基于AntPathMatcher的,而Spring Boot 2.6.X使用的是PathPatternMatcher。
解决:在application.properties里配置:spring.mvc.pathmatch.matching-strategy=ANT_PATH_MATCHER。

java.lang.TypeNotPresentException: Type javax.servlet.http.HttpServletRequest not present
	at java.base/sun.reflect.generics.factory.CoreReflectionFactory.makeNamedType(CoreReflectionFactory.java:117) ~[na:na]
	...
	at java.base/java.lang.Class.forName(Class.java:467) ~[na:na]
	at java.base/sun.reflect.generics.factory.CoreReflectionFactory.makeNamedType(CoreReflectionFactory.java:114) ~[na:na]
	... 34 common frames omitted

在application.properties文件中加入以下配置

spring.mvc.pathmatch.matching-strategy=ANT_PATH_MATCHER

解决上面的报错便可以启动项目,但是还不能访问http://localhost:8080/swagger-ui.html (未能解决)

六、任务

6.1 异步任务

  1. 新建一个service包,包下建一个AsyncTask类

    package com.shu.service;
    
    import org.springframework.scheduling.annotation.Async;
    import org.springframework.stereotype.Service;
    
    @Service
    public class AsyncTask {
        //告诉Spring这是一个异步的方法
        @Async
        public void hello(){
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("数据正在处理...");
        }
    }
    
  2. 新建一个controller包,包下建一个AsyncController类

    package com.shu.controller;
    
    import com.shu.service.AsyncTask;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class AsyncController {
        @Autowired
        AsyncTask asyncTask;
    
        @RequestMapping("/hello")
        public String hello(){
            asyncTask.hello();如果不开启异步异步任务会停止三秒,转圈~;开启异步任务秒刷新,不会转圈
            return "OK";
        }
    }
    
  3. 在启动类上增加@EnableAsync 注解

    package com.shu;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.scheduling.annotation.EnableAsync;
    
    @EnableAsync //开启异步注解的功能
    @SpringBootApplication
    public class SpringBootTaskApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(SpringBootTaskApplication.class, args);
        }
    
    }
    
  4. 测试秒刷新,不会等三秒才会出现OK!

    image-20221222164615245

6.2 定时任务

TaskScheduler //任务调度者
TaskExecutor //任务执行者
@EnableScheduling //开启定时功能的注解,启动类上加
@Scheduled //什么时候执行

6.2.1 扩展:cron表达式

Cron表达式是一个字符串,字符串以5或6个空格隔开,分为6或7个域,每一个域代表一个含义,Cron有如下两种语法格式:

(1) Seconds Minutes Hours DayofMonth Month DayofWeek Year

(2)Seconds Minutes Hours DayofMonth Month DayofWeek

一、结构

corn从左到右(用空格隔开):秒 分 小时 月份中的日期 月份 星期中的日期 年份

二、各字段的含义

image-20221222183131243

注意事项:

每一个域都使用数字,但还可以出现如下特殊字符,它们的含义是:

(1):表示匹配该域的任意值。假如在Minutes域使用, 即表示每分钟都会触发事件。

(2)?:只能用在DayofMonth和DayofWeek两个域。它也匹配域的任意值,但实际不会。因为DayofMonth和DayofWeek会相互影响。例如想在每月的20日触发调度,不管20日到底是星期几,则只能使用如下写法: 13 13 15 20 * ?, 其中最后一位只能用?,而不能使用*,如果使用*表示不管星期几都会触发,实际上并不是这样。

(3)-:表示范围。例如在Minutes域使用5-20,表示从5分到20分钟每分钟触发一次

(4)/:表示起始时间开始触发,然后每隔固定时间触发一次。例如在Minutes域使用5/20,则意味着5分钟触发一次,而25,45等分别触发一次.

(5),:表示列出枚举值。例如:在Minutes域使用5,20,则意味着在5和20分每分钟触发一次。

(6)L:表示最后,只能出现在DayofWeek和DayofMonth域。如果在DayofWeek域使用5L,意味着在最后的一个星期四触发。

(7)W:表示有效工作日(周一到周五),只能出现在DayofMonth域,系统将在离指定日期的最近的有效工作日触发事件。例如:在 DayofMonth使用5W,如果5日是星期六,则将在最近的工作日:星期五,即4日触发。如果5日是星期天,则在6日(周一)触发;如果5日在星期一到星期五中的一天,则就在5日触发。另外一点,W的最近寻找不会跨过月份 。

(8)LW:这两个字符可以连用,表示在某个月最后一个工作日,即最后一个星期五。

(9)#:用于确定每个月第几个星期几,只能出现在DayofMonth域。例如在4#2,表示某月的第二个星期三。

三、常用表达式例子

(1)0 0 2 1 * ? * 表示在每月的1日的凌晨2点调整任务

(2)0 15 10 ? * MON-FRI 表示周一到周五每天上午10:15执行作业

(3)0 15 10 ? 6L 2002-2006 表示2002-2006年的每个月的最后一个星期五上午10:15执行作

(4)0 0 10,14,16 * * ? 每天上午10点,下午2点,4点

(5)0 0/30 9-17 * * ? 朝九晚五工作时间内每半小时

(6)0 0 12 ? * WED 表示每个星期三中午12点

(7)0 0 12 * * ? 每天中午12点触发

(8)0 15 10 ? * * 每天上午10:15触发

(9)0 15 10 * * ? 每天上午10:15触发

(10)0 15 10 * * ? * 每天上午10:15触发

(11)0 15 10 * * ? 2005 2005年的每天上午10:15触发

(12)0 * 14 * * ? 在每天下午2点到下午2:59期间的每1分钟触发

(13)0 0/5 14 * * ? 在每天下午2点到下午2:55期间的每5分钟触发

(14)0 0/5 14,18 * * ? 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发

(15)0 0-5 14 * * ? 在每天下午2点到下午2:05期间的每1分钟触发

(16)0 10,44 14 ? 3 WED 每年三月的星期三的下午2:10和2:44触发

(17)0 15 10 ? * MON-FRI 周一至周五的上午10:15触发

(18)0 15 10 15 * ? 每月15日上午10:15触发

(19)0 15 10 L * ? 每月最后一日的上午10:15触发

(20)0 15 10 ? * 6L 每月的最后一个星期五上午10:15触发

(21)0 15 10 ? * 6L 2002-2005 2002年至2005年的每月的最后一个星期五上午10:15触发

(22)0 15 10 ? * 6#3 每月的第三个星期五上午10:15触发

注:

(1)有些子表达式能包含一些范围或列表

例如:子表达式(天(星期))可以为 “MON-FRI”,“MON,WED,FRI”,“MON-WED,SAT”

“*”字符代表所有可能的值

因此,“”在子表达式(月)里表示每个月的含义,“”在子表达式(天(星期))表示星期的每一天

“/”字符用来指定数值的增量
  例如:在子表达式(分钟)里的“0/15”表示从第0分钟开始,每15分钟
在子表达式(分钟)里的“3/20”表示从第3分钟开始,每20分钟(它和“3,23,43”)的含义一样

“?”字符仅被用于天(月)和天(星期)两个子表达式,表示不指定值
  当2个子表达式其中之一被指定了值以后,为了避免冲突,需要将另一个子表达式的值设为“?”

“L” 字符仅被用于天(月)和天(星期)两个子表达式,它是单词“last”的缩写
  但是它在两个子表达式里的含义是不同的。
  在天(月)子表达式中,“L”表示一个月的最后一天
  在天(星期)自表达式中,“L”表示一个星期的最后一天,也就是SAT

如果在“L”前有具体的内容,它就具有其他的含义了

例如:“6L”表示这个月的倒数第6天,“FRIL”表示这个月的最一个星期五
  注意:在使用“L”参数时,不要指定列表或范围,因为这会导致问题

6.2.2 案例实践

  1. 开启定时功能的注解

    package com.shu;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.scheduling.annotation.EnableAsync;
    import org.springframework.scheduling.annotation.EnableScheduling;
    
    @EnableScheduling //开启定时功能的注解
    @EnableAsync //开启异步注解的功能
    @SpringBootApplication
    public class SpringBootTaskApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(SpringBootTaskApplication.class, args);
        }
    
    }
    
  2. 编写代码

    package com.shu.service;
    
    import org.springframework.scheduling.annotation.Scheduled;
    import org.springframework.stereotype.Service;
    
    import java.text.SimpleDateFormat;
    import java.time.LocalDateTime;
    import java.util.Date;
    
    import static com.fasterxml.jackson.databind.type.LogicalType.DateTime;
    
    @Service
    public class ScheduledService {
        //在一个固定的时间执行这个方法~ Timer
    
        //cron 表达式
        // 0 * * * * 0-7 : 合起来就表示,每一天的任何时候的第0秒都会执行一次
        // 秒 分 时 日 月 周几:0-7 就表示每一天
        //@Scheduled(cron = "0 * * * * 0-7")
        @Scheduled(cron = "0 26 18 * * ?")  //表示:每一天 18:16:00 的时候执行一次
        //@Scheduled(cron = "30 0/5 10,18 * * ?")  //表示:每天10点,18点,每隔五分钟执行一次
        public void hello(){
            //打印当前时间
            //方法一
            LocalDateTime localDateTime = LocalDateTime.now();
            System.out.println(localDateTime);
            //方法二
            SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            System.out.println(format.format(new Date()));
    
            System.out.println("hello,你被执行了~");
        }
    }
    
  3. 测试

    image-20221222182643323

6.3 邮件任务

  1. 导入mail依赖

    <!--导入 javax.mail 包:配置-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-mail</artifactId>
    </dependency>
    
  2. 在application.properties文件中添加如下配置

    spring.mail.username=1795386527@qq.com
    spring.mail.password=govpyumjgyfmehia
    spring.mail.host=smtp.qq.com
    #开启加密验证:QQ才有!其他邮箱不需要
    spring.mail.properties.mail.smtp.ssl.enable = true
    
  3. password获取方法

    • 登录qq邮箱

      image-20221222171208184

    • 找到账户

      image-20221222171259824

    • 开启POP3/SMTP服务

      image-20221222171341722

    • 得到密码

      image-20221222171438352

  4. 在测试类中编写如下代码

    package com.shu;
    
    import jakarta.annotation.Resource;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.mail.SimpleMailMessage;
    import org.springframework.mail.javamail.JavaMailSenderImpl;
    
    @SpringBootTest
    class SpringBootTaskApplicationTests {
        @Resource
        JavaMailSenderImpl mailSender;
    
        @Test
        void contextLoads() {
    
            //一个简单的邮件发送
            SimpleMailMessage mailMessage = new SimpleMailMessage();
    
            mailMessage.setSubject("小舒,你好!");
            mailMessage.setText("今天也要元气满满哟!");
            mailMessage.setTo("1795386527@qq.com"); //可以发送给自己
            mailMessage.setFrom("1795386527@qq.com"); 
    
            mailSender.send(mailMessage);
        }
    
    }
    
  5. 执行测试类,测试通过即可收到邮件

    image-20221222171641537

  6. 一个复杂邮件发送

    @Test
    void contextLoads2() throws MessagingException {
    
        //一个复杂的邮件发送
        MimeMessage mimeMessage = mailSender.createMimeMessage();
        //组装
        MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true,"utf-8");
        //正文
        helper.setSubject("小舒,你好~plus");
        helper.setText("<p style='color:red'>今天也要元气满满哟~plus</p>",true);
    
        //附件
        helper.addAttachment("Go.jpg",new File("C:\\Users\\kevin\\Desktop\\Go.jpg"));
    
        helper.setTo("1795386527@qq.com"); //可以发送给自己
        helper.setFrom("1795386527@qq.com");
        mailSender.send(mimeMessage);
    }
    
  7. 测试执行成功即可收到邮件

    image-20221222173926866

    image-20221222173856716

  8. 封装成一个方法

    /**
     * 发送邮件
     * @param html
     * @param subject
     * @param text
     * @throws MessagingException
     * @Author xiaoshu
     */
    public void sendMail(Boolean html,String subject,String text) throws MessagingException{
        //一个复杂的邮件发送
        MimeMessage mimeMessage = mailSender.createMimeMessage();
        //组装
        MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,html,"utf-8");
        //正文
        helper.setSubject(subject);
        helper.setText(text,true);
    
        //附件
        helper.addAttachment("Go.jpg",new File("C:\\Users\\kevin\\Desktop\\Go.jpg"));
    
        helper.setTo("1795386527@qq.com"); //可以发送给自己
        helper.setFrom("1795386527@qq.com");
        mailSender.send(mimeMessage);
    }
    

七、分布式 Dubbo+Zookeeper+SpringBoot

7.1 分布式理论

什么是分布式系统?
在《分布式系统原理与范型》一书中有如下定义: “分布式系统是若干独立计算机的集合,这些计算机对于用户来说就像单个相关系统”;

分布式系统是由一组通过网络进行通信、为了完成共同的任务而协调工作的计算机节点组成的系统。分布式系统的出现是为了用廉价的、普通的机器完成单个计算机无法完成的计算、存储任务。其目的是利用更多的机器,处理更多的数据

分布式系统 (distributed system) 是建立在网络之上的软件系统。

首先需要明确的是,只有当单个节点的处理能力无法满足日益增长的计算、存储任务的时候,且硬件的提升(加内存、加磁盘、使用更好的CPU)高昂到得不偿失的时候,应用程序也不能进一步优化的时候,我们才需要考虑分布式系统。因为,分布式系统要解决的问题本身就是和单机系统一样的,而由于分布式系统多节点、通过网络通信的拓扑结构,会引入很多单机系统没有的问题,为了解决这些问题又会引入更多的机制、协议,带来更多的问题。。。

Dubbo文档

官网:https://cn.dubbo.apache.org/zh/

随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,急需一个治理系统确保架构有条不紊的演进。
在Dubbo的官网文档有这样一张图

image-20221223110621441

单一应用架构
当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。此时,用于简化增删改查工作量的数据访问框架(ORM)是关键。

适用于小型网站,小型管理系统,将所有功能都部署到一个功能里,简单易用。缺点:
1、性能扩展比较难
2、协同开发问题
3、不利于升级维护

垂直应用架构
当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,将应用拆成互不相干的几个应用,以提升效率。此时,用于加速前端页面开发的Web框架(MVC)是关键。

通过切分业务来实现各个模块独立部署,降低了维护和部署的难度,团队各司其职更易管理,性能扩展也更方便,更有针对性。
缺点:公用模块无法重复利用,开发性的浪费

分布式服务架构
当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。此时,用于提高业务复用及整合的分布式服务框架RPC是关键。

流动计算架构
当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率,此时,用于提高机器利用率的资源调度和治理中心(SOA)[ Service Oriented Architecture]是关键.

7.2 RPC

什么是RPC?
RPC[Remote Procedure Cal] 是指远程过程调用,是一种进程间通信方式,他是一种技术的思想,而不是规范。它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数,而不用程序员显式编码这个远程调用的细节。即程序员无论是调用本地的还是远程的函数,本质上编写的调用代码基本相同。
也就是说两台服务器A,B,一个应用部署在A服务器上,想要调用B服务器上应用提供的函数/方法,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义和传达调用的数据。为什么要用RPC呢? 就是无法在一个进程内,甚至个计算机内通过本地调用的方式完成的需求,比如不同的系统间的通讯,其至不同的组织间的通讯,由于计算能力需要椅向扩展,需要在多台机器组成的集群上部署应用。RPC就是要像调用本地的函数一样去调远程函数

推荐阅读文章: https://www.jianshu.com/p/2accc2840a1b

RPC基本原理

image-20221223113022380

步骤解析:

image-20221223114235877

RPC的两个核心模块:通信、序列化(方便数据传输:数据传输需要转换)

7.3 Dubbo概念

Apache Dubbo 是一款 RPC 服务开发框架,用于解决微服务架构下的服务治理与通信问题,官方提供了 Java、Golang 等多语言 SDK 实现。使用 Dubbo 开发的微服务原生具备相互之间的远程地址发现与通信能力, 利用 Dubbo 提供的丰富服务治理特性,可以实现诸如服务发现、负载均衡、流量调度等服务治理诉求。Dubbo 被设计为高度可扩展,用户可以方便的实现流量拦截、选址的各种定制逻辑。

Dubbo3 定义为面向云原生的下一代 RPC 服务框架。3.0 基于 Dubbo 2.x 演进而来,在保持原有核心功能特性的同时, Dubbo3 在易用性、超大规模微服务实践、云原生基础设施适配、安全性等几大方向上进行了全面升级。

7.3.1 Dubbo 是什么

Apache Dubbo |'dʌbəʊ|是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力: 面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。

Apache Dubbo 最初在 2008 年由 Alibaba 捐献开源,很快成为了国内开源服务框架选型的事实标准框架 ,得到了各行各业的广泛应用。在 2017 年,Dubbo 正式捐献到 Apache 软件基金会并成为 Apache 顶级项目,目前 Dubbo3 已经是一站式的微服务解决方案提供:

  • 基于 HTTP/2 的 Triple 协议以及面向代理 API 的编程体验。
  • 强大的流量治理能力,如地址发现、负载均衡、路由选址、动态配置等。
  • 多语言 SDK 实现,涵盖 Java、Golang、Javascript 等,更多语言实现将会陆续发布。
  • 灵活的适配与扩展能力,可轻松与微服务体系其他组件如 Tracing、Transaction 等适配。
  • Dubbo Mesh 解决方案,同时支持 Sidecar、Proxyless 等灵活的 Mesh 部署方案。

Dubbo架构图

arch-service-discovery

  • 服条提供者 (Provider): 暴露服务的服务提供方,服务提供者在启动时,向注册中心注册自己提供的服务
  • 服务消费者(Consumer):调用远程服务的服务消费方,服务消费者在启动时,向注册中心订阅自己所需的服务,服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
  • 注册中心(Registry):注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者
  • 监控中心(Monitor):服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心

调用关系说明

  • 服务容器负责启动,加载,运行服务提供者。
  • 服务提供者在启动时,向注册中心注册自己提供的服务
  • 服务消费者在启动时,向注册中心订阅自己所需的服务
  • 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
  • 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
  • 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

Apache Dubbo 总体架构能很好的满足企业的大规模微服务实践,因为它从设计之初就是为了解决超大规模微服务集群实践问题,不论是阿里巴巴还是工商银行、中国平安、携程等社区用户,它们都通过多年的大规模生产环境流量对 Dubbo 的稳定性与性能进行了充分验证,因此,Dubbo 在解决业务落地与规模化实践方面有着无可比拟的优势:

  • 开箱即用
    • 易用性高,如 Java 版本的面向接口代理特性能实现本地透明调用
    • 功能丰富,基于原生库或轻量扩展即可实现绝大多数的微服务治理能力
  • 面向超大规模微服务集群设计
    • 极致性能,高性能的 RPC 通信协议设计与实现
    • 横向可扩展,轻松支持百万规模集群实例的地址发现与流量治理
  • 高度可扩展
    • 调用过程中对流量及协议的拦截扩展,如 Filter、Router、LB 等
    • 微服务治理组件扩展,如 Registry、Config Center、Metadata Center 等
  • 企业级微服务治理能力
    • 国内公有云厂商支持的事实标准服务框架
    • 多年企业实践经验考验,参考用户实践案例

7.3.2 Dubbo环境搭建

点进dubbo官方文档,推荐我们使用Zookeeper注册中心:

https://cn.dubbo.apache.org/zh/docs3-v2/java-sdk/reference-manual/registry/zookeeper/

什么是Zookeeper呢?可以自行查看上面的官方文档

windows下安装Zookeeper

  1. 下载地址,我们下载最新版:

    https://www.apache.org/dyn/closer.lua/zookeeper/zookeeper-3.8.0/apache-zookeeper-3.8.0-bin.tar.gz

  2. 运行/bin/zkServer.cmd ,初次运行会报错,没有zoo.cfg配置文件;

    可能遇到问题: 闪退!
    解决方案: 编辑zkServer.cmd文件末尾添加pause 。这样运行出错就不会退出,会提示错误信息,方便找到原因。

    • 如下

    image-20221223182300815

    • 报错

      image-20221223182735951

    • 去路径下将 zoo_sample.cfg 配置文件复制一份命名为 zoo.cfg

      image-20221223182812800

    • 配置文件了解

      # The number of milliseconds of each tick
      tickTime=2000
      # The number of ticks that the initial 
      # synchronization phase can take
      initLimit=10
      # The number of ticks that can pass between 
      # sending a request and getting an acknowledgement
      syncLimit=5
      # the directory where the snapshot is stored.
      # do not use /tmp for storage, /tmp here is just 
      # example sakes.
      dataDir=/tmp/zookeeper
      # the port at which the clients will connect
      clientPort=2181
      # the maximum number of client connections.
      # increase this if you need to handle more clients
      #maxClientCnxns=60
      #
      # Be sure to read the maintenance section of the 
      # administrator guide before turning on autopurge.
      #
      # https://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
      #
      # The number of snapshots to retain in dataDir
      #autopurge.snapRetainCount=3
      # Purge task interval in hours
      # Set to "0" to disable auto purge feature
      #autopurge.purgeInterval=1
      
      ## Metrics Providers
      #
      # https://prometheus.io Metrics Exporter
      #metricsProvider.className=org.apache.zookeeper.metrics.prometheus.PrometheusMetricsProvider
      #metricsProvider.httpHost=0.0.0.0
      #metricsProvider.httpPort=7000
      #metricsProvider.exportJvmInfo=true
      

      image-20221223183055443

    • 重新运行/bin/zkServer.cmd,便可启动成功

      image-20221223183438496

  3. 注意修改zoo.cfg配置文件
    将conf文件夹下面的zoo sample.cfg复制一份改名为zoo.cfg即可
    注意几个重要位置:
    dataDir=/tmp/zookeeper 临时数据存储的目录 (可写相对路径)
    clientPort=2181 zookeeper的端口号
    修改完成后再次运行/bin/zkServer.cmd

    image-20221223183957789

  4. 运行/bin/zkServer.cmd,使用zkCli.cmd测试

    不运行会报错

    image-20221223184801694

    连接成功

    image-20221223185101496

    ls /:列出zookeeper根下保存的所有节点

    image-20221223185240232

    create -e /xiaoshu 123: 创建一个xiaoshu节点,值为123

    image-20221223185508601

    get /xiaoshu: 获取/xiaoshu节点的值

    image-20221223185606697

windows下安装dubbo-admin

dubbo本身并不是一个服务软件。它其实就是一个jar包,能够帮你的java程序连接到zookeeper,并利用zookeeper消费、提供服务。
但是为了让用户更好的管理监控众多的dubbo服务,官方提供了一个可视化的监控程序dubbo-admin,不过这个监控即使不装也不影响使用。
我们这里来安装一下,下载dubbo-admin
地址 : https://github.com/apache/dubbo-admin/tree/master

通过源码打包运行

  1. 下载代码: git clone https://github.com/apache/dubbo-admin.git

  2. dubbo-admin-server/src/main/resources/application.properties中指定注册中心地址

    image-20221226101921371

  3. 在项目目录下打包dubbo-admin

    • mvn clean package -Dmaven.test.skip=true

    出现如下错误,则需要安装Apache Maven的环境(环境变量也要配置,类似于java环境配置)

    image-20221226102508623

    1. 下载地址:https://maven.apache.org/download.cgi

    2. 下载apache-maven-3.8.6-bin.zip

      image-20221226102735426

    3. 新建环境变量

      image-20221226103410446

    4. 在path中新增

      image-20221226103712923

    5. 最后测试一下是否安装成功

      image-20221226103850709

    6. 出现上面的页面说明安装成功了

    7. 重新进命令mvn clean package -Dmaven.test.skip=true

      image-20221226104239788

    8. 出现上面的页面就说明命令执行成功了,但是第一次打包东西有点多,有点慢;完事之后就会生成一个jar包

      image-20221226104708734

    9. 出现上面的页面说明打包成功,然后继续执行下面的步骤

  4. 启动

    • mvn --projects dubbo-admin-server spring-boot:run 或者
    • cd dubbo-admin-distribution/target; java -jar dubbo-admin-${project.version}.jar

    image-20221226105246234

  5. 这时候我没有开Zookeeper所以会报如下错误

    image-20221226105434084

  6. 所以需要打开Zookeeper,步骤在上面有说

    image-20221226105741162

  7. 然后重新执行jar包,这边显示我的8080端口被占用了,我们使用netstat -ano | findstr "8080"命令查看端口号的进程pid

    image-20221226111025652

  8. 过滤出需要释放的端口后,在cmd窗口输入taskkill命令可释放被占用的端口,然后杀死该进程重新启动

    taskkill -f -t /pid "占用端口的程序的pid"       
    参数详解:
    /T                     终止指定的进程和由它启用的子进程。
    /F                     指定强制终止进程。
    注:其余参数可使用 TASKKILL /? 命令查看
    

    image-20221226111412637

  9. 重新运行jar包,还是不行(Tomcat默认开启的端口号就是8080,一直显示被占用,我也不知道是什么原因),不管了,我们去把服务端口号给改成7001后重新打包后运行jar包

    image-20221226112836655

  10. 访问 http://localhost:7001

    默认用户名、密码都是:root,登录之后进入Dubbo Admin页面

    image-20221226114217459

总结:

Zookeeper:注册中心

Dubbo-admin:是一个监控管理后台,可以查看我们注册了哪些服务,哪些服务被消费了(可以不用,但是注册中心必须有)

Dubbo:jar包

核心:Zookeeper和Dubbo的jar包

7.4 服务注册发现实战(可自行查看官方教程)

官方教程:https://cn.dubbo.apache.org/zh/docs3-v2/java-sdk/quick-start/spring-boot/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/115596.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LeetCode 每日一题——1759. 统计同构子字符串的数目

1.题目描述 1759. 统计同构子字符串的数目 难度中等43 给你一个字符串 s &#xff0c;返回 s 中 同构子字符串 的数目。由于答案可能很大&#xff0c;只需返回对 109 7 取余 后的结果。 同构字符串 的定义为&#xff1a;如果一个字符串中的所有字符都相同&#xff0c;那么…

Rancher RFO 正式 GA

Rancher RFO GA RFO 是 Rancher For openEuler 的缩写&#xff0c;旨在面向 openEuler 打造 Rancher 基础平台。其中最核心的工作是打造一款面向 openEuler 生态的 Kubernetes 发行版。它基于上游 RKE2 的技术栈&#xff0c;构建物采用 openEuler base image&#xff0c;致力于…

C语言及算法设计课程实验一:C程序的运行环境和运行C程序的方法

C语言及算法设计课程实验一&#xff1a;C程序的运行环境和运行C程序的方法一、实验目的二、实验内容2.1、输人并运行一个简单的正确的程序2.2、输人并编辑一个有错误的C程序2.3、输入并运行一个需要在运行时输入数据的程序2.4、运行一个自己编写的程序三、实验步骤3.1、输人并运…

Android OpenGL ES 学习(十一) –渲染YUV视频以及视频抖音特效

OpenGL 学习教程 Android OpenGL ES 学习(一) – 基本概念 Android OpenGL ES 学习(二) – 图形渲染管线和GLSL Android OpenGL ES 学习(三) – 绘制平面图形 Android OpenGL ES 学习(四) – 正交投影 Android OpenGL ES 学习(五) – 渐变色 Android OpenGL ES 学习(六) – 使用…

基于MWORKS.Sysplorer的电子控制器应用案例——永磁同步电机FOC算法建模

1 前言 MWORKS是面向数字工程的新一代科学计算与系统建模仿真平台&#xff0c;可提供机械、电子、液压、控制、热、信息等多领域统一建模仿真环境。经过同元持续攻关&#xff0c;全新推出的MWORKS.Sysplorer嵌入式代码生成器&#xff0c;现已支持面向电子控制器的产品级的嵌入…

循环神经网络的简洁实现

参考8.6. 循环神经网络的简洁实现 — 动手学深度学习 2.0.0 documentation 本节将展示如何使用深度学习框架的高级API提供的函数更有效地实现相同的语言模型。 我们仍然从读取时光机器数据集开始。 pip install mxnet1.7.0.post1 pip install d2l0.15.0 from mxnet import n…

ubuntu18.04下用Fiddler抓取curl库网络数据包总结

本人在ubuntu18.04下进行开发&#xff0c;需要使用http和服务端进行通信&#xff0c;为了确认自己发送给服务端和服务端返回数据字段&#xff0c;所以需要进行抓包分析参数。本文就说明一下如何在ubuntu18.04使用fidder对自己编写的应用程序进行http协议数据包抓取。 目录 1.…

无线网络渗透测试清单

©网络研究院 无线渗透测试积极检查 WiFi 网络中的信息安全措施的过程&#xff0c;并分析弱点、技术流程和关键无线漏洞。 我们应该关注的最重要的对策是威胁评估、数据盗窃检测、安全控制审计、风险预防和检测、信息系统管理和升级基础设施&#xff0c;并且应该准备一份…

13-14-15-RabbitMq工作模式深度剖析与Spring整合MQ以及RabbitMq高级特性

RabbitMQ消息传递流程 连接( Connection) 在RabbitMQ中&#xff0c;生产者和消费者与RabbitMQ的通信就是基于TCP连接的。不过呢我们知道TCP连接的创建和销毁在高并发场景下对于操作系统来说都是特别昂贵的开销&#xff0c;所以RabbitMQ又引入了信道的概念 信道&#xff08;Chan…

云原生之使用Docker部署轻量级web服务器lighthttpd

云原生之使用Docker部署轻量级web服务器lighthttpd一、Lighthttpd介绍二、检查系统版本三、检查docker状态四、下载lighthttpd镜像五、部署lighthttpd1.创建数据目录2.创建lighthttpd容器3.查看容器状态六、访问lighthttpd服务七、编辑index.html1.编辑index.html文件2.重新访问…

Hadoop大数据存算分离方案:计算层无缝对接存储系统

Hadoop的诞生改变了企业对数据的存储、处理和分析的过程&#xff0c;加速了大数据的发展。随着大数据系统建设的深入&#xff0c;企业的数据基础设施易出现计算资源浪费、存储性能低、管理成本过高等挑战。相比存算一体架构&#xff0c;存算分离架构具有性能与成本最优、兼具灵…

3D地图app

3D三维地图APP 发布时间&#xff1a;2018-07-19 版权&#xff1a; 3D地图依据高程数据等对地表进行渲染&#xff0c;实现地表的起伏&#xff0c;模拟出真实的三维场景&#xff0c;让你有如身临其境般的感觉。 &#xff08;注&#xff1a;Bigemap 3D地图是一个三维地图浏览功能…

项目沟通怎么才能不像在吵架?

项目沟通并非吵架&#xff0c;看起来却总是剑拔弩张。有效沟通才能真正解决问题&#xff0c;笔者给出了一些实用的建议&#xff0c;从对象到场景&#xff0c;再到方法与技巧&#xff0c;应该在沟通中有针对性地注意这些问题。 沟通是个老话题&#xff0c;在项目管理中有专门讲沟…

draw.io使用教程

大部分的绘图应用都离不开三个基本的元素&#xff0c;图形&#xff0c;链接&#xff0c;文本。每个元素都有基本的操作和样式&#xff0c;元素与元素之间又可以进行组合&#xff0c;“三生万物”&#xff0c;生成各种各样的图表。 如果没有这款绘图的 可以点击获取 : drawio文…

企业项目管理的不同与好处

大型企业组织通常同时运行多个复杂项目。尽管这些项目看起来不一定相互关联&#xff0c;但它们都会影响同一个企业组织。企业项目管理(EPM)是指在公司范围内管理项目的实践。它通常涉及实施战略和流程&#xff0c;以大规模简化和提高项目管理的有效性。根据项目管理协会(PMI)的…

burpsuite靶场——XXE

文章目录什么是XML&#xff1f;什么是XML实体&#xff1f;什么是文档类型定义(DTD)&#xff1f;什么是XML自定义实体&#xff1f;什么是XML外部实体&#xff1f;使用外部实体利用 XXE 来检索文件利用 XXE 执行 SSRF 攻击盲XXE漏洞带外交互的盲 XXE过 XML 参数实体进行带外交互的…

【AJAX】AJAX的跨域问题

AJAX的跨域问题跨域的概述区别同源与不同源同源策略有什么用&#xff1f;AJAX跨域解决方案方案一、设置响应头方案二、jsonp方案三、代理机制&#xff08;httpclient&#xff09;跨域的概述 跨域是指从一个域名的网页去请求另一个域名的资源。比如从百度&#xff08;https://ba…

WPF控件模板、数据模板、容器样式选择器

WPF控件模板 利用Tag来绑定控件模板内容 <!--模板定义--> <Style x:Key"ButtonStyle1" TargetType"{x:Type Button}"><Setter Property"Template"><Setter.Value><ControlTemplate TargetType"{x:Type Button…

声音事件检测metric:PSDS

论文&#xff1b;A FRAMEWORK FOR THE ROBUST EVALUATION OF SOUND EVENT DETECTION Abstract 这项工作为多声道声音事件检测&#xff08;SED&#xff09;系统的性能评估定义了一个新的框架&#xff0c;它克服了传统的collar-based事件决定、事件F-cores和事件错误率的限制。…

【Kotlin 协程】Flow 流组合 ( Flow#zip 组合多个流 | 新组合流的元素收集间隔与被组合流元素发射间隔的联系 )

文章目录一、Flow 流组合1、Flow#zip 组合多个流2、新组合流的元素收集间隔与被组合流元素发射间隔的联系一、Flow 流组合 1、Flow#zip 组合多个流 调用 Flow#zip 函数 , 可以将两个 Flow 流合并为一个流 ; Flow#zip 函数原型 : /*** 将来自当前流( this )的值压缩到[其他]流&…