SpringBoot

SpringBoot

微服务阶段

  • javase: OOP
  • mysql:持久化
  • html+css+js+jquery+框架
  • javaweb:MVC 三层架构 的网站
  • ssm:简化了开发流程 配置也相对复杂
  • Spring:
  • SpringBoot:内嵌Tomact 微服务架构
  • springCloud

在这里插入图片描述

SpringBoot

SpringBoot 是基于 Spring 的开发 SpringBoot 本身不提供Spring 框架的核心特性以及扩展性功能 只是用于快速开发一代基于Spring 框架的应用程序 他不是用来替代Spring的解决方法, 而是和Spring紧密结合用于提升Spring开发体验的

Spring Boot 约定大于配置 默认帮我们进行了很多设置 多数SpringBoot 应用只需要很少的Spring配置

同时集成了大量的常用第三方库配置(Redis,MongoDB,Jpa,RabbitMQ,Quartz …) Spring Boot 中这些第三方库几乎可以零配置

SpringBoot 其实不是什么新的框架 它默认配置了很多框架的使用方法 就像maven整合了所有的jar包 SpringBoot 整合了所有的框架

优点:

  • 为所有Spring开发者更快的入门
  • 开箱即可 提供各种默认配置来简化项目配置
  • 内嵌式容器简化Web项目
  • 没有冗余代码生成和XML配置的要求
微服务

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

单体应用架构(all in one)

将一个应用中的所有应用服务都封装在一个应用中

  • 易于开发和测试 也十分方便部署 当需要扩展时 只需要将 war 复制多份 然后放在多个服务器上 再做个负载均衡就可以了
  • 缺点 : 哪怕要修改一个非常小的地方 都需要停掉整个服务 重新打包 部署 war包
微服务架构

all in one 的架构方式 我们把所有的功能单元放在一个应用里面 然后我们把整个应用部署到服务器上 如果负 载能力不行 我们将整个应用进行水平复制 进行扩展 然后在负载均衡

微服务架构 就是打破之前 all in one 的架构方式 把每个功能元素独立出来 把独立出来的功能元素的动态组合 需要的功能元素才拿来组合 需要多一些时可以整合多个功能元素 所以微服务架构是对功能元素进行复制 而没有对整个应用进行复制

好处:

  • 节省了调用资源
  • 每个功能元素的服务都是一个可替代的 可独立升级的软件代码

怎么样构建微服务

  • 构建一个个功能独立的微服务应用单元 可以使用 SpringBoot 可以帮我们快速构建一个应用
  • 大型分布式网络服务的调用 这部分有SpringCloud 来完成 实现分布式
  • 在分布式中间 进行流式数据计算 批处理 使用 spring cloud data flow
  • spring 为我们提供了从开始构建应用到大型分布式应用全流程方案

Hello Word:

  • jdk 1.8
  • maven 3.6.1
  • springboot
  • IDEA
方式一:

在 官网 直接下载后 导入 idea 开发

Spring 官网:

在这里插入图片描述

项目结构:

在这里插入图片描述

HelloworldApplication :程序的主入口 不能修改 所有的包都要创建在 它的同级目录下 不然无法访问

helloController

@RestController
public class helloController {@RequestMapping("/hello")public String Hello(){//调用业务接收前端的参数return "hello world!!!";}
}

运行:

在这里插入图片描述

在这里插入图片描述

  • 项目元数据:创建时输入的 Project Metadata 部分 也就是Maven 项目的基本元素 包括:groupid artifactld version name description 等等

  • parent:继承 spring-boot-starter-parent 的依赖管理 控制版本与打包等内容

  • dependencies:项目具体依赖 这里包括 spring-boot-strater-web 用于实现 HTTP 接口 (该接口包含 Spring MVC )

    • 使用Spring MVC 构建Web (包括Restful)应用程序的入门者 使用Tomact 作为默认嵌入式容器

    spring-boot-starter-test :用于编写单元测试的依赖包

  • build:构建配置部分 默认使用 spring-boot-maven-plugin 配合 spring-boot-starter-parent 就可以把 Spring Boot 应用打包成 JAR 运行。

方式二:

使用idea 创建一个springboot 项目

在这里插入图片描述

helloController

//SpringBoot 完成一件事: 自动装配@RestController
@RequestMapping("/hello")
public class helloController {@ResponseBody@RequestMapping("/hello")public String Hello(){//调用业务接收前端的参数return "hello world!!!";}
}

application.properties

# 更改项目访问的端口号
server.port=8081

banner.txt

                        [{+?]~++++{.!{{{{[}}{{{{{_.   .{++++{   {{}{{++++++{++++++?}]++?{{_++{  -{++++}{+rr+r\+{+++++{$$ +++++++[{<<+++++{}++++++{+++++++{<{}+{$k {+++++}}{^}{++[{++++++++++++++{   _++++++++{,{++++++++++++++++++]}?+++++++++++{{{++++++++++++++++++++++++++++++}{{+++++++++++++++++++++++_++++{{+++++++++++++++++++}}}}}}}++I{+++++++++++++++++++[}}}}}}}_+{[]++vY+++++++++++++++}}}}}}}}++{{++++X$X|+++++++++++++}}}}}[+++{{_++++X%$$qXXv\|XXX)++++++++++-^.     :{++++++XX$$$$$qXv++++++++++++{l-++++++++++++++++++++++++++{I{++++++++++++++++++++++++{C0{}++++++++++++++++++-{0CCOOOOO0{{[+++++++++_{{0OOO0CCOOOOOOOOOOOOOOUCOOOOOOOOOOOOn<<<""<<CLOOOOOOOOOOOOOOOOOOOOOOOOOOOOC   ;<<<<<<<<<. COOOOOOOOOOOOOOOOOOOOOOOOOOOOOOC     <<<<!<<.   COOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOCz<;!>    COOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOC{QOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOL   'COOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOY"< <COOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOC<<<<<<`'COOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOC[COOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOC]CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC<<             ^<^<<             ^<^<<             ^<^$$$$$$$$>      O$$$$$$$z

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.5.5</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.zhang</groupId><artifactId>SpringBoot-study-01</artifactId><version>0.0.1-SNAPSHOT</version><name>SpringBoot-study-01</name><description>SpringBoot-study-01</description><properties><java.version>1.8</java.version></properties><!--版本号不用写 它会继承父依赖--><dependencies><!--启动器--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build><repositories><repository><id>aliyunmaven</id><url>https://maven.aliyun.com/repository/public</url><releases><enabled>true</enabled></releases><snapshots><enabled>false</enabled></snapshots></repository></repositories><pluginRepositories><pluginRepository><id>nexus-aliyun</id><name>Nexus-aliyun</name><url>https://maven.aliyun.com/repository/public</url><snapshots><enabled>false</enabled></snapshots><releases><enabled>true</enabled></releases></pluginRepository></pluginRepositories>
</project>

运行:

在这里插入图片描述

原理

自动配置

pom.xml

  • spring-boot-dependencies: 核心依赖在父工程中
  • 我们在或 引入一些SpringBoot 依赖的时候不需要指定版本 因为有版本仓库管理
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.5.5</version><relativePath/> <!-- lookup parent from repository -->
</parent>

启动器

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId>
</dependency>
  • 就是springboot的启动场景
  • 比如 spring-boot-starter-web 就会帮我们导入 web 所需要的所有环境
  • spring boot 会将所有的功能场景变成一个个 启动器 starter
  • 我们要什么功能 只需要找到对应的启动器即可

主程序

// @SpringBootApplication :标注这个类是一个 springboot 的应用 程序 
@SpringBootApplication
public class SpringBootStudy01Application {// 将spring boot 应用启动public static void main(String[] args) {SpringApplication.run(SpringBootStudy01Application.class, args);}
}

注解:

@SpringBootConfiguration   : springboot 的配置@Configuration :spring 配置类@Component: 说明也是一个spring的组件@EnableAutoConfiguration : 自动配置@AutoConfigurationPackage : 自动配置包@Import(AutoConfigurationPackages.Registrar.class) :自动配置 包注册@Import(AutoConfigurationImportSelector.class) : 自动配置导入选择

SpringApplication.run:

该方法·主要分为两部分 一部分是 springApplication 的实例 二是run方法 的执行

SpringApplication:

  • 推断应用的类型是普通的项目 还是web 项目
  • 查找并加载所有的可用初始化器 设置到initializers 属性中
  • 找出所有的应用程序监听器 设置到 listeners 属性中
  • 推断并设置 main 方法的定义类 找到运行的主类

SpringBoot 配置文件

配置文件:使用一个 全局的配置文件

  • application.properties
    • 语法: key = value
  • application.yml
    • 语法: key: 空格 value

配置文件的作用:

修改springboot 的默认配置

yaml

标记语言:以前的配置文件 大多数是用xml 来配置

xml 配置

<server><port>8081</port>
</server>

yaml 配置:

server:prot: 8081

application.yaml

替代 application.properties

# 对空格要求十分严格
# 可以注入到配置类中
# 普通的 k-v
name: xiaotao# 对象
student:name: xiaotaoage: 18# 行内写法
student1: {name: xiaotao,age: 18}# 数组
pets:- cat- dog- pigpers: [cat,dog,pig]

实体类:

Dog

@Component
@Data
public class Dog {@Value("旺财")private String name;@Value("3")private Integer age;
}

Person

@Component
@Data
@ConfigurationProperties(prefix = "person")
public class Person {private String name;private Integer age;private Boolean happy;private Date birth;private Map<String,Object> map;private List<Object> list;private Dog dog;
}

application.yaml

# 通过 yaml 给实体类赋值
person:name: xiaotaoage: 18happy: truebirth: 2021/10/31map: {k1: v1,k2: v2}list:- code- music- girldog:name: 旺财age: 2

测试

@SpringBootTest
class SpringBootStudy01ApplicationTests {@Autowiredprivate Person person;@Testvoid contextLoads() {System.out.println(person);}}

在这里插入图片描述

pom.xml

添加依赖即可解决

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional>
</dependency>

运行:

image-20211031124942773

# 通过 yaml 给实体类赋值
person:name: xiaotao${random.uuid}   # 产生一个随机的 uuidage: ${random.int}happy: truebirth: 2021/10/31map: {k1: v1,k2: v2}list:- code- music- girldog:name: ${person.hello:hello}_旺财   # 如果 person.hello 存在则取 对应值 否则 取 helloage: 2

image-20211031130915987

image-20211031130937378

yaml 及 properties 对比

image-20211031131203537

松散绑定

image-20211031132034167

在这里插入图片描述

在这里插入图片描述

JSR303 数据校验

在字段增加一层过滤器验证 可以保证数据的合法性

Bean Validation 中内置的 constraint

3145530-8ae74d19e6c65b4c

Hibernate Validator 附加的 constraint

3145530-10035c6af8e90a7c

多环境配置

application.properties

在这里插入图片描述

application.yaml

使用yaml 一个配置文件即可以

通过 --- 即可区分不同配置环境

server:port: 8081
spring:profiles:active: dev---
server:port: 8082
spring:profiles: dev---
server:port: 8083
spring:profiles: test

自动装配原理

  • SpringBoot 启动会加载大量的自动配置类

  • 我们看我们需要的功能有没有在SpringBoot 默认写好的自动配置类中

  • 看这个自动配置类中到底配置了哪些组件· 只要我们要用到的组件存在其中 我们就不需要手动配置了

  • 给容器中自动配置类添加组件的时候 会从·properties类中获取属性 我们只需要在配置文件中指定这些属性的值即可

    xxxAutoConfigurartion: 自动配置类 给容器添加组件

    xxxProperties : 封装配置文件中相关属性

debug = true  # 开启日志 查看哪些自动配置类生效 哪些没有生效

Springboot Web 开发

自动配置

SpringBoot 到底帮我们配置了什么? 我们能不能修改? 能修改什么? 能不能扩展?

  • xxxAutoConfiguraion 向容器中自动配置组件
  • xxxProperties : 自动配置类 装配配置文件中自定义的一些内容

要解决的问题:

  • 导入静态资源
  • 首页
  • jsp 模板引擎 Thymeleaf
  • 装配扩展SpringMVC
  • 增删改查
  • 拦截器
  • 国际化

静态资源

https://www.webjars.org/

方式一: 以 maven 的方式引入静态资源 (不推荐)

<dependency><groupId>org.webjars.npm</groupId><artifactId>jquery</artifactId><version>3.6.0</version>
</dependency>

方式二: 放在 classpath:static classpath:public classpath:resources 文件夹下面

Thymeleaf

在 templates 目录下的所有页面 只能通过controller 来跳转
需要模板引擎的支持 thymeleaf
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

引入命名空间

<html lang="en" xmlns:th="www.thymeleaf.arg">

在这里插入图片描述

首页

所有的静态资源都需要使用 thylemeaf 接管

url : @{}

页面国际化

  • 我们需要配置 I18n 文件
  • 我们需要在项目中进行按钮自动切换 需要自定义一个组件 LocaleResolver
  • 将组件 配置到 Spring 容器中托管 @Bean
  • #{}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8vNNGdtH-1690941414317)(http://qiniu.xiaotao.cloud/QQ截图20211105001121.png)]

CRUD

数据库

无论是 sql(关系型数据库) 还是 nosql(非关系型数据库)springboot 都是采用 SpringData 的方式进行统一管理

JDBC

JDBCController

@RestController
public class JDBCController {@AutowiredJdbcTemplate jdbcTemplate;@GetMapping("/userList")public List<Map<String,Object>> userList(){String sql = "select * from stuinfo";List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql);return maps;}@GetMapping("/addUser")public String addUser(){String sql = "insert into stuinfo values('T123100','小灰灰','女',19,'重庆')";int i = jdbcTemplate.update(sql);return "addUser";}@GetMapping("/update")public String update(){String sql = "update stuinfo set stu_name = '小涛',stu_sex = '女',stu_age = 18,stu_Address = '重庆'  where stu_id = 'T123005';";int i = jdbcTemplate.update(sql);return "update";}@GetMapping("/del/{id}")public String del(@PathVariable("id") String id){String sql = "delete from stuinfo where stu_id = ?";int i = jdbcTemplate.update(sql,id);return "del";}
}
Druid

application.yaml

spring:datasource:username: rootpassword: 123456url: jdbc:mysql://localhost:3306/mybatis?useUniocde=true&characterEncoding=utf-8&serverTimezone=UTCdriver-class-name: com.mysql.cj.jdbc.Drivertype: com.alibaba.druid.pool.DruidDataSource    # 指定使用 Druid 数据源#Spring Boot 默认是不注入这些属性值的,需要自己绑定#druid 数据源专有配置initialSize: 5minIdle: 5maxActive: 20maxWait: 60000timeBetweenEvictionRunsMillis: 60000minEvictableIdleTimeMillis: 300000validationQuery: SELECT 1 FROM DUALtestWhileIdle: truetestOnBorrow: falsetestOnReturn: falsepoolPreparedStatements: true#配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入#如果允许时报错  java.lang.ClassNotFoundException: org.apache.log4j.Priority#则导入 log4j 依赖即可,Maven 地址:https://mvnrepository.com/artifact/log4j/log4jfilters: stat,wall,log4jmaxPoolPreparedStatementPerConnectionSize: 20useGlobalDataSourceStat: trueconnectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

DriverConfig

@Configuration
public class DriverConfig {/*** 使自定义配置 druid 生效* @return*/@ConfigurationProperties(prefix = "spring.datasource")@Beanpublic DataSource druidDataSource(){return new DruidDataSource();}// 后台监控 运行访问 http://localhost:8080/druid@Beanpublic ServletRegistrationBean statViewServlet(){ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");// 后台需要有人登录 账号 密码 配置HashMap<String,String> initParameters = new HashMap<>();// 增加配置// 登录的 key 是固定的  loginUsername  loginPasswordinitParameters.put("loginUsername","admin");initParameters.put("loginPassword","123456");// 允许谁能访问  值为空 代表 任何人都可以initParameters.put("allow","");// 禁止谁访问//initParameters.put("xiaotao","192.168.42.233");bean.setInitParameters(initParameters);  // 设置初始化参数return bean;}
}
后台监控

访问: http://localhost:8080/druid

在这里插入图片描述

在这里插入图片描述

执行一次查询

在这里插入图片描述

监控到

在这里插入图片描述

过滤
//filter
public FilterRegistrationBean webStatFilter(){FilterRegistrationBean bean = new FilterRegistrationBean();HashMap<String,String> initParameters = new HashMap<>();initParameters.put("exclusions","*.js,*.css,/druid/*");   // 这些不统计bean.setInitParameters(initParameters);bean.setFilter(new WebStatFilter());return bean;
}
Mybatis
  • 导入包
<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.3.2</version>
</dependency>
  • 配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zhang.mapper.StuInfoMapper"><select id="queryStuList" resultType="StuInfo">select * from stuinfo</select>
</mapper>
  • mybatis配置
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver# 整合mybatis
mybatis.type-aliases-package=com.zhang.pojo
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
  • mapper service controller

SpringSecurity (安全) 权限

  • 在 web 开发中 安全第一位
  • 安全应该在设计之初考虑
  • 漏洞 隐私泄露
shiro SpringSecurity

两个都是用于安全的框架 很像 除了类不一样

认证 授权

  • 功能权限
  • 访问权限
  • 菜单权限
  • 原来 拦截器 过滤器 …
  • 现在框架

springSecurity 是针对 spring 项目的安全框架 样式 SpringBoot底层安全模块默认的选形 他可以实现强大的web 安全控制 外面只需要 引入

进行少量的配置 即可实现强大的web安全管理

  • WebSecurityConfigurerAdapter:自定义 Security 模式
  • :自定义认证策略
  • @EnableWebSecurity:开启WebSecurity 模式 @Enablexxx : 开启莫个功能

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

认证(Authentication)

授权(Authorization)

SpringSecurity

导入包:

<!--security-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId>
</dependency>

在这里插入图片描述

SecurityConfig

/*** 权限 管理  通过 AOP 横切*/
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {/*** 授权* @param http* @throws Exception*/@Overrideprotected void configure(HttpSecurity http) throws Exception {// 首页所有人可以访问 功能页只有对应有权限的人才能访问// 链式编程// antMatchers("/"):代表哪些页面// permitAll():所有人都可以访问// hasRole("vip1") : 指定人可以访问http.authorizeRequests().antMatchers("/").permitAll().antMatchers("/level1/**").hasRole("vip1").antMatchers("/level2/**").hasRole("vip2").antMatchers("/level3/**").hasRole("vip3");// 没有权限默认会到登录页面  需要开启登录的页面 会走默认的页面  http://localhost:8080/login// loginPage("/toLogin") : 定制自己的登录页面// 框架默认使用的是 username  password 要使用 不同的可以加上下面的属性http.formLogin().loginPage("/toLogin").usernameParameter("user").passwordParameter("pwd").loginProcessingUrl("/login");// 开启注销功能// 他会有防止网站攻击: 只能使用 post 请求// 不加需要 post 请求 才能注销http.csrf().disable();  // 关闭 csrf 功能 可以使用 get 请求   (解决不能注销问题)http.logout().logoutSuccessUrl("/");//开启记住我 cookie 默认保存两周  自定义接收前端参数http.rememberMe().rememberMeParameter("remember");}/*** 认证* @param auth* @throws Exception*/@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {// 从内存中获取// 需要进行密码加密auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder()).withUser("xiaotao").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2").and().withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3").and().withUser("guest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1");// 也可以从数据库中获取// auth.jdbcAuthentication().withUser("").password("").roles("");}
}

RouterController

@Controller
public class RouterController {@RequestMapping({"/","/index"})public String index(){return "index";}@RequestMapping("/toLogin")public String login(){return "views/login";}@RequestMapping("/level1/{id}")public String level1(@PathVariable("id") Integer id){return "views/level1/"+id;}@RequestMapping("/level2/{id}")public String level2(@PathVariable("id") Integer id){return "views/level2/"+id;}@RequestMapping("/level3/{id}")public String level3(@PathVariable("id") Integer id){return "views/level3/"+id;}
}

实现有什么权限看到那个页面:

<!--security thymeleaf 整合-->
<dependency><groupId>org.thymeleaf.extras</groupId><artifactId>thymeleaf-extras-springsecurity4</artifactId><version>3.0.4.RELEASE</version>
</dependency>

在这里插入图片描述

 <!--登录注销-->
<div class="right menu"><!--如果未登录--><div sec:authorize="!isAuthenticated()"><a class="item" th:href="@{/toLogin}"><i class="address card icon"></i> 登录</a></div><!--如果已登录--><div sec:authorize="isAuthenticated()"><!--用户名--><a class="item" >用户名:<span sec:authentication="name"></span><!--角色:<span sec:authentication="principal.getAuthorities()"></span>--></a><!--注销--><a class="item" th:href="@{/logout}"><i class="sign-out icon"></i> 注销</a></div>
</div>
<!--sec:authorize="hasRole('vip1')" : 假如有 vip1 权限显示-->
<div class="column" sec:authorize="hasRole('vip1')"><div class="ui raised segment"><div class="ui"><div class="content"><h5 class="content">Level 1</h5><hr><div><a th:href="@{/level1/1}"><i class="bullhorn icon"></i> Level-1-1</a></div><div><a th:href="@{/level1/2}"><i class="bullhorn icon"></i> Level-1-2</a></div><div><a th:href="@{/level1/3}"><i class="bullhorn icon"></i> Level-1-3</a></div></div></div></div>
</div>
shiro
  • Apache shiro 是一个java 的安全权限框架
  • shiro 可以非常容易的开发出足够好的应用 不仅可以在 javaSE 环境 也可以在 javaEE 环境
  • shiro 可以完成 认证 授权 加密 会话管理 web集成 缓存

在这里插入图片描述

subject: 用户

SecurityManager:管理所有用户

Realm:连接数据

快速开始
  • 导入依赖
<dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-core</artifactId><version>1.8.0</version>
</dependency><!-- configure logging -->
<dependency><groupId>org.slf4j</groupId><artifactId>jcl-over-slf4j</artifactId><version>1.7.21</version>
</dependency>
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.21</version>
</dependency>
<dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version>
</dependency>
  • log4j.properties
log4j.rootLogger=INFO, stdoutlog4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n# General Apache libraries
log4j.logger.org.apache=WARN# Spring
log4j.logger.org.springframework=WARN# Default Shiro logging
log4j.logger.org.apache.shiro=INFO# Disable verbose logging
log4j.logger.org.apache.shiro.util.ThreadContext=WARN
log4j.logger.org.apache.shiro.cache.ehcache.EhCache=WARN
  • shiro.ini
[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
  • Quickstart.java
public class Quickstart {private static final transient Logger log = LoggerFactory.getLogger(Quickstart.class);public static void main(String[] args) {Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");SecurityManager securityManager = factory.getInstance();SecurityUtils.setSecurityManager(securityManager);// 获取当前的用户对象 subjectSubject currentUser = SecurityUtils.getSubject();// 通过当前用户得到 sessionSession session = currentUser.getSession();session.setAttribute("someKey", "aValue");String value = (String) session.getAttribute("someKey");if (value.equals("aValue")) {log.info("subject=>session====> [" + value + "]");}// 测试当前用户是否被认证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?}}//获取当前用户的信息log.info("User [" + currentUser.getPrincipal() + "] logged in successfully.");//判断当前用户是否具有该权限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!");}//注销currentUser.logout();// 结束系统System.exit(0);}
}
SpringBoot 集成 shiro
  • 导入依赖
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><!--shiro 整合 Spring 的包 --><!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring --><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring</artifactId><version>1.7.1</version></dependency><!--shiro 整合 thymeleaf 的包 --><dependency><groupId>com.github.theborakompanioni</groupId><artifactId>thymeleaf-extras-shiro</artifactId><version>2.0.0</version></dependency><!--mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!-- druid --><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.8</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.22</version></dependency><!--log4j--><dependency><groupId>com.att.inno</groupId><artifactId>log4j</artifactId><version>1.2.13</version></dependency><!-- mybatis-spring-boot-starter --><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.3.2</version></dependency><!--thymeleaf--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>

在这里插入图片描述

IndexController

@Controller
public class IndexController {@RequestMapping({"/","/index","index.html"})public String index(Model model){model.addAttribute("msg","hello shiro");return "index";}@RequestMapping("/user/add")public String add(){return "/user/add";}@RequestMapping("/user/update")public String update(){return "/user/update";}@RequestMapping("/toLogin")public String toLogin(){return "login";}@RequestMapping("/login")public String login(String username,String password,Model model){// 获取当前用户Subject subject = SecurityUtils.getSubject();// 封装用户登录数据UsernamePasswordToken token = new UsernamePasswordToken(username, password);try {subject.login(token);   // 执行了登录方法return "index";} catch (UnknownAccountException uae) {   // 用户名不存在model.addAttribute("msg","用户名错误");return "login";} catch (IncorrectCredentialsException ice) { // 密码错误model.addAttribute("msg","密码错误");return "login";} catch (LockedAccountException lae) {  // 账户被锁定model.addAttribute("msg","账户被锁定");return "login";}}/*** 未授权页面* @return*/@RequestMapping("/unauth")@ResponseBodypublic String unauthorized(){return "没有授权不能访问此页面";}
}

ShiroConfig

@Configuration
public class ShiroConfig {// 第三步  ShiroFilterFactoryBean@Beanpublic ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();// 设置安全管理器factoryBean.setSecurityManager(defaultWebSecurityManager);// 添加shiro 的内置过滤器/*** anon: 无需认证就可以访问* authc:必须认证了才能访问* user:必须拥有记住我 才能实现* perms:拥有对某个资源的权限才能访问* role:拥有某个角色权限才能访问*/Map<String, String> filterMap = new LinkedHashMap<>();// 授权filterMap.put("/user/add","perms[user:add]");filterMap.put("/user/update","perms[user:update]");// 拦截/*filterMap.put("/user/add","authc");filterMap.put("/user/update","authc");*/// 可以使用通配符filterMap.put("/user/*","authc");factoryBean.setFilterChainDefinitionMap(filterMap);// 设置登录页面factoryBean.setLoginUrl("/toLogin");// 设置未授权页面factoryBean.setUnauthorizedUrl("/unauth");return factoryBean;}// 第二步 DefaultWebSecurityManager@Bean(name = "securityManager")                            //@Qualifier("userRealm") userRealm: 为下面的方法名 或 name 都可以public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();// 关联 realmsecurityManager.setRealm(userRealm);return securityManager;}// 第一步 创建 realm 需要自定义类@Bean(name = "userRealm")     // 或 @Bean(name = "userRealm")public UserRealm userRealm(){return new UserRealm();}// 整合shiro thymeleaf@Beanpublic ShiroDialect getShiroDialect(){return new ShiroDialect();}}

UserRealm

/*** 自定义 realm*/
public class UserRealm extends AuthorizingRealm {@AutowiredUserService userService;/*** 授权* @param principalCollection* @return*/@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {System.out.println("执行了 ==》 授权 doGetAuthorizationInfo");SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();//获取到当前登录的对象Subject subject = SecurityUtils.getSubject();User currentUSer = (User) subject.getPrincipal();//设置当前用户的权限info.addStringPermission(currentUSer.getPerms());return info;}/*** 认证* @return* @throws AuthenticationException*/@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {System.out.println("执行了 ==》 认证 doGetAuthenticationInfo");UsernamePasswordToken userToken = (UsernamePasswordToken) token;// 用户名  数据库中获取User user = userService.queryUserByName(userToken.getUsername());if(user==null){return null;   //抛出异常}// 把当前登录用户存入sessionSubject currentSubject = SecurityUtils.getSubject();currentSubject.getSession().setAttribute("loginUser",user);// 密码认证 shiro 会自己实现return new SimpleAuthenticationInfo(user,user.getPwd(),"");  //这里必须存入 user 上面才能获取}
}

UserMapper

@Mapper
@Repository
public interface UserMapper {User queryUserByName(String name);
}

index.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.arg"xmlns:shiro="http://www.thymeleaf.arg/thymeleaf-extras-shiro">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><h1>首页</h1><p th:if="${session.loginUser==null}"><a th:href="@{/toLogin}">登录</a></p><h3 th:text="${msg}"></h3>
<hr/><div shiro:hasPermission="user:add"><a th:href="@{/user/add}">add</a></div><div shiro:hasPermission="user:update"><a th:href="@{/user/update}">update</a></div>
</body>
</html>

application.yaml

spring:datasource:username: rootpassword: 123456url: jdbc:mysql://localhost:3306/mybatis?useUniocde=true&characterEncoding=utf-8&serverTimezone=UTCdriver-class-name: com.mysql.cj.jdbc.Drivertype: com.alibaba.druid.pool.DruidDataSource    # 指定使用 Druid 数据源#Spring Boot 默认是不注入这些属性值的,需要自己绑定#druid 数据源专有配置initialSize: 5minIdle: 5maxActive: 20maxWait: 60000timeBetweenEvictionRunsMillis: 60000minEvictableIdleTimeMillis: 300000validationQuery: SELECT 1 FROM DUALtestWhileIdle: truetestOnBorrow: falsetestOnReturn: falsepoolPreparedStatements: true#配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入#如果允许时报错  java.lang.ClassNotFoundException: org.apache.log4j.Priority#则导入 log4j 依赖即可,Maven 地址:https://mvnrepository.com/artifact/log4j/log4jfilters: stat,wall,log4jmaxPoolPreparedStatementPerConnectionSize: 20useGlobalDataSourceStat: trueconnectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

Swagger

学习目标:

  • 了解Swgger 的作用及概念
  • 了解前后端分离
  • 在SpringBoot中集成Swagger

简介

前后端分离:

Vue + SpringBoot

后端时代:前端只用管理静态页面 html ===》后端 模板引擎 jsp

前后端分离时代:

后端:控制层 服务层 数据访问层

前端:控制层 试图访问层

​ 伪后端数据 json

前后端如何交互 ====》 API

前后端相对独立 松耦合

前后端甚至可以部署在不同的服务器上

问题:

前后端继承联调 前后端人员无法做到“及时协商 今早解决” 最后导致问题爆发

解决方案:

首先制定 schema 【计划提纲】 实时更新最新API 降低集成风险

  • 原来:指定 word 计划文档
  • 前后端分离:
    • 前端测试后端接口: postman
    • 后端提供接口 需要实时更新最新的消息及改动

Swagger

  • 世界上 最流行的API 框架
  • RestFul Api 文档在线自动生成工具 =》 Api 文档与 api 定义同时更新
  • 直接运行 可以在线测试 Api 接口
  • 支持多种语言 :java php …

SpringBoot 集成 Swagger

在项目中使用Swagger需要springfox

导入依赖

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

Config 配置:

@Configuration
@EnableSwagger2     // 开启 swagger2
public class SwaggerConfig {}

测试运行: swagger-ui.html

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xNLsWfZ2-1690941414320)(http://qiniu.xiaotao.cloud/QQ截图在这里插入图片描述
.png)]

配置 swagger 基本信息
@Configuration
@EnableSwagger2     // 开启 swagger2
public class SwaggerConfig {// 配置了 Swagger的Docket 的bean 实例@Beanpublic Docket docket(){return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo());}// 配置 swagger 信息 apiInfopublic ApiInfo apiInfo(){// 作者信息Contact contact = new Contact("小涛","https://www.xiaotao.cloud/","2177393158@qq.com");return new ApiInfo("xiaotao 的 SwaggerApi ","即使再小的帆也能远航!","1.0","https://www.xiaotao.cloud/",contact,"Apache 2.0","http://www.apache.org/licenses/LICENSE-2.0",new ArrayList());}
}
Swagger 配置扫描接口
// 配置了 Swagger的Docket 的bean 实例@Beanpublic Docket docket(){return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select()// RequestHandlerSelectors: 配置要扫描接口的方式// .basePackage("com.zhang.controller"): 指定要扫描的包// .any():  扫描全部// .none(): 不扫描// .withClassAnnotation(RestController.class): 扫描类上的注解 参数是一个注解的反射对象// .withMethodAnnotation(GetMapping.class): 扫描方法上的注解.apis(RequestHandlerSelectors.basePackage("com.zhang.controller"))// paths: 过滤什么路径.paths(PathSelectors.ant("/zhang/**")).build();} 
配置是否启动 Swagger
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).enable(true)  // 默认为 true 改为false 则不能使用.select().apis(RequestHandlerSelectors.basePackage("com.zhang.controller")).build();
实现在开发的时候使用swagger 上线时不使用swagger
@Beanpublic Docket docket(Environment environment){// 实现在开发的时候使用swagger 扫描 上线时不使用swagger//设置要显示的环境Profiles profiles = Profiles.of("dev", "test");// 通过 environment.acceptsProfiles 判断是否处于自己设定的环境中boolean flag = environment.acceptsProfiles(profiles);return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).enable(flag)   // flag : true false.select().apis(RequestHandlerSelectors.basePackage("com.zhang.controller")).build();}

配置Api分组:

.groupName("xiaotao")

配置 多个分组:

@Bean
public Docket docket1(){return new Docket(DocumentationType.SWAGGER_2).groupName("A");
}@Bean
public Docket docket2(){return new Docket(DocumentationType.SWAGGER_2).groupName("B");
}@Bean
public Docket docket3(){return new Docket(DocumentationType.SWAGGER_2).groupName("C");
}

在这里插入图片描述

接口注释

实体类

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

controller

@RestController
public class HelloController {@GetMapping("/hello")public String hello(){return "hello word";}// 只要接口中 返回值存在 实体类 他就会被 扫描到 swagger 中@PostMapping("/user")public User user(){return new User();}//Operation 接口@ApiOperation("Hello 控制类")@GetMapping("/hello2")public String hello2(@ApiParam("用户名") String username){return "hello"+username;}@ApiOperation("post 测试控制类")@PostMapping("/postt")public User postt(@ApiParam("用户") User user){return user;}
}

总结:

  • 我们可以使用 swagger 给一些比较难理解的属性或接口 增加注释信息
  • 接口文档实时更新
  • 可以在线测试
  • 注: 在正式发布时 关闭swagger 这样更加安全 节省内存

任务

异步任务
@Service
public class AsyncService {// 告诉 spring 这是一个 异步请求@Asyncpublic void hello(){try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("数据正在处理.....");}
}
@RestController
public class AsyncController {@Autowiredprivate AsyncService asyncService;@RequestMapping("/hello")public String hello(){asyncService.hello();  //  不使用异步注解  停止 3秒return "ok";}
}

主启动类

@EnableAsync // 开启异步请求注解
@SpringBootApplication
public class SpringBootTask08Application {public static void main(String[] args) {SpringApplication.run(SpringBootTask08Application.class, args);}}
定时任务
TaskScheduler  任务调度者
TaskExecutor   任务执行者@EnableScheduling  开启定时功能的注解
@Scheduled    什么时候执行

主启动类

@EnableAsync // 开启异步请求的注解
@EnableScheduling // 开启定时功能的注解
@SpringBootApplication
public class SpringBootTask08Application {public static void main(String[] args) {SpringApplication.run(SpringBootTask08Application.class, args);}
}
@Service
public class ScheduledService {/*** 在特定的时间执行* cron : 表达式* 秒 分 时 日 月 周几*/@Scheduled(cron = "0 * * * * 0-7")public void hello(){System.out.println("hello 我出来啦!");}
}
常用表达式例子(10/2 * * * * ?   表示每2秒 执行任务(10 0/2 * * * ?    表示每2分钟 执行任务(10 0 2 1 * ?   表示在每月的1日的凌晨2点调整任务(20 15 10 ? * MON-FRI   表示周一到周五每天上午10:15执行作业(30 15 10 ? 6L 2002-2006   表示2002-2006年的每个月的最后一个星期五上午10:15执行作(40 0 10,14,16 * * ?   每天上午10点,下午2点,4点 (50 0/30 9-17 * * ?   朝九晚五工作时间内每半小时 (60 0 12 ? * WED    表示每个星期三中午12点 (70 0 12 * * ?   每天中午12点触发 (80 15 10 ? * *    每天上午10:15触发 (90 15 10 * * ?     每天上午10:15触发 (100 15 10 * * ?    每天上午10:15触发 (110 15 10 * * ? 2005    2005年的每天上午10:15触发 (120 * 14 * * ?     在每天下午2点到下午2:59期间的每1分钟触发 (130 0/5 14 * * ?    在每天下午2点到下午2:55期间的每5分钟触发 (140 0/5 14,18 * * ?     在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发 (150 0-5 14 * * ?    在每天下午2点到下午2:05期间的每1分钟触发 (160 10,44 14 ? 3 WED    每年三月的星期三的下午2:102:44触发 (170 15 10 ? * MON-FRI    周一至周五的上午10:15触发 (180 15 10 15 * ?    每月15日上午10:15触发 (190 15 10 L * ?    每月最后一日的上午10:15触发 (200 15 10 ? * 6L    每月的最后一个星期五上午10:15触发 (210 15 10 ? * 6L 2002-2005   2002年至2005年的每月的最后一个星期五上午10:15触发 (220 15 10 ? * 6#3   每月的第三个星期五上午10:15触发
邮件任务
  • 导入依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId>
</dependency>
  • 配置文件
spring.mail.username=2177393158@qq.com
spring.mail.password=ktdihwxprzqveaad     
spring.mail.host=smtp.qq.com# 开启加密验证 (qq才需要)
spring.mail.properties.mail.smtp.ssl.enable=true
  • 测试
@Autowired
JavaMailSenderImpl mailSender;/*** 简单的邮件*/
@Test
void contextLoads() {SimpleMailMessage mailMessage = new SimpleMailMessage();mailMessage.setSubject("hello xiaotao");mailMessage.setText("嘿嘿嘿嘿嘿嘿嘿嘿嘿嘿嘿嘿");mailMessage.setTo("2177393158@qq.com");mailMessage.setFrom("2177393158@qq.com");mailSender.send(mailMessage);
}/*** 复杂的邮件*/
@Test
void contextLoads2() throws MessagingException {MimeMessage mimeMessage = mailSender.createMimeMessage();// 组装MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true);//正文helper.setSubject("hello xiaotao");helper.setText("<p style='color:red'>嘿嘿嘿嘿嘿嘿嘿嘿嘿嘿嘿嘿</P>",true);// 附件helper.addAttachment("1.jpg",new File("D:\\01.jpg"));helper.addAttachment("2.jpg",new File("D:\\01.jpg"));helper.setTo("2177393158@qq.com");helper.setFrom("2177393158@qq.com");mailSender.send(mimeMessage);
}

分布式 Dubbo + Zookeeper + SpringBoot

什么是分布式系统:

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

分布式系统(distributed system)是建立在网络之上的软件系统。正是因为软件的特性,所以分布式系统具有高度的内聚性和透明性。因此,网络和分布式系统之间的区别更多的在于高层软件(特别是操作系统),而不是硬件

利用更多的机器 处理更多的数据

只有当单个机器无法处理的时候我们才会考虑使用分布式

详细概念

https://mp.weixin.qq.com/s/sKu9-vH7NEpUd8tbxLRLVQ

Zookeeper 安装

Zookeeper : 注册中心

下载:http://archive.apache.org/dist/zookeeper/

在这里插入图片描述

管理员身份

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

Dubbo 安装

Dubbo : 一个jar包

下载dubbo-admin

地址 :https://github.com/apache/dubbo-admin/tree/master-0.2.0

在这里插入图片描述

先要启动 (管理员)

zkServer.cmd :打开 zookeeper 服务

去cmd 运行(管理员身份)

java -jar dubbo-admin-0.0.1-SNAPSHOT.jar

访问:

在这里插入图片描述

在这里插入图片描述

dubbo-admin : 是一个监控管理后台 查看我们注册了那些服务· 那些服务被消费了

SpringBoot 整合 Dubbo + Zookeeper

新建项目

在这里插入图片描述

在这里插入图片描述

服务提供者

导入依赖:

<!-- Dubbo Spring Boot Starter -->
<dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-spring-boot-starter</artifactId><version>2.7.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.github.sgroschupf/zkclient -->
<dependency><groupId>com.github.sgroschupf</groupId><artifactId>zkclient</artifactId><version>0.1</version>
</dependency><!-- 引入zookeeper -->
<dependency><groupId>org.apache.curator</groupId><artifactId>curator-framework</artifactId><version>2.12.0</version>
</dependency>
<dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId><version>2.12.0</version>
</dependency>
<dependency><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId><version>3.4.14</version><!--排除这个slf4j-log4j12--><exclusions><exclusion><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId></exclusion></exclusions>
</dependency>

application.properties

server.port=8081#当前应用名字
dubbo.application.name=provider-server
#注册中心地址
dubbo.registry.address=zookeeper://127.0.0.1:2181
#扫描指定包下服务
dubbo.scan.base-packages=com.zhang.service

TicketServiceImpl

package com.zhang.service;import org.apache.dubbo.config.annotation.Service;
import org.springframework.stereotype.Component;@Service  // dubbo :下的 在项目一启动就自动注到注册中心
@Component //使用了dubbo 后尽量不要用 service 注解 会和上一个冲突
public class TicketServiceImpl implements TicketService{@Overridepublic String getTicket() {return "小涛 你好呀!!";}
}

先要启动 (管理员)

zkServer.cmd :打开 zookeeper 服务

去cmd 运行(管理员身份)

java -jar dubbo-admin-0.0.1-SNAPSHOT.jar

启动项目:

provider-server

在这里插入图片描述

在这里插入图片描述

服务消费者

导入依赖:(同上)

<!-- Dubbo Spring Boot Starter -->
<dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-spring-boot-starter</artifactId><version>2.7.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.github.sgroschupf/zkclient -->
<dependency><groupId>com.github.sgroschupf</groupId><artifactId>zkclient</artifactId><version>0.1</version>
</dependency><!-- 引入zookeeper -->
<dependency><groupId>org.apache.curator</groupId><artifactId>curator-framework</artifactId><version>2.12.0</version>
</dependency>
<dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId><version>2.12.0</version>
</dependency>
<dependency><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId><version>3.4.14</version><!--排除这个slf4j-log4j12--><exclusions><exclusion><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId></exclusion></exclusions>
</dependency>

application.properties

server.port=8082#当前应用名字
dubbo.application.name=consumer-server
#注册中心地址
dubbo.registry.address=zookeeper://127.0.0.1:2181

UserService

package com.zhang.service;import org.apache.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Service;@Service  // 放到spring 容器中
public class UserService {// 获取到 provider-server 提供的票  需要去注册中心那到服务/*** 两种方式:* 1. pom 坐标* 2. 定义路径相同的接口名*/// 这里使用的是 路径相同的接口名@Reference // 引用TicketService ticketService;public void buyTicket(){String ticket = ticketService.getTicket();System.out.println("在注册中心拿到票===> "+ticket);}
}

TicketService

public interface TicketService {public String getTicket();
}

测试:

@SpringBootTest
class ConsumerServerApplicationTests {@AutowiredUserService userService;@Testvoid contextLoads() {userService.buyTicket();}}

在这里插入图片描述

启动项目

在这里插入图片描述

在这里插入图片描述

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

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

相关文章

云原生全栈体系(二)

Kubernetes实战入门 第一章 Kubernetes基础概念 一、是什么 我们急需一个大规模容器编排系统kubernetes具有以下特性&#xff1a; 服务发现和负载均衡 Kubernetes 可以使用 DNS 名称或自己的 IP 地址公开容器&#xff0c;如果进入容器的流量很大&#xff0c;Kubernetes 可以负…

CSS调色网有哪些

本文章转载于湖南五车教育&#xff0c;仅用于学习和讨论&#xff0c;如有侵权请联系 1、https://webgradients.com/ Wbgradients 是一个在线调整渐变色的网站 &#xff0c;可以根据你想要的调整效果&#xff0c;同时支持复制 CSS 代码&#xff0c;可以更好的与开发对接。 Wbg…

经典CNN(三):DenseNet算法实战与解析

&#x1f368; 本文为&#x1f517;365天深度学习训练营中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊|接辅导、项目定制 1 前言 在计算机视觉领域&#xff0c;卷积神经网络&#xff08;CNN&#xff09;已经成为最主流的方法&#xff0c;比如GoogleNet&#xff0c;…

opencv 30 -图像平滑处理01-均值滤波 cv2.blur()

什么是图像平滑处理? 图像平滑处理&#xff08;Image Smoothing&#xff09;是一种图像处理技术&#xff0c;旨在减少图像中的噪声、去除细节并平滑图像的过渡部分。这种处理常用于预处理图像&#xff0c;以便在后续图像处理任务中获得更好的结果。 常用的图像平滑处理方法包括…

C++ 左值和右值

C 左值和右值 左值、右值左值引用、右值引用std::move()std::move()的实现引用折叠 完美转发forward()的实现函数返回值是左值还是右值如何判断一个值是左值还是右值 左值、右值 在C11中所有的值必属于左值、右值两者之一&#xff0c;右值又可以细分为纯右值、将亡值。在C11中…

OpenShot 发布 2.3.2 版本啦!

导读OpenShot 2.3.3 发布了&#xff0c;Openshot 是 linux 的 Gnome 桌面一个非线性视频编辑器&#xff0c;有许多功能&#xff1a;你可以重划大小&#xff0c;修剪或者剪切视频&#xff0c;同时有实时的预览&#xff0c;图片覆盖&#xff0c;标题模板&#xff0c;视频解码&…

web前端框架Javascript之JavaScript 异步编程史

早期的 Web 应用中&#xff0c;与后台进行交互时&#xff0c;需要进行 form 表单的提交&#xff0c;然后在页面刷新后给用户反馈结果。在页面刷新过程中&#xff0c;后台会重新返回一段 HTML 代码&#xff0c;这段 HTML 中的大部分内容与之前页面基本相同&#xff0c;这势必造成…

PHP 前后端分离,运行配置

H5 WEB目录:安装 yarn install、npm install &#xff08;依赖包&#xff09; 在电脑&#xff1a;安装nodejs Composer下载 &#xff1a;https://getcomposer.org/

性能测试,python 内存分析工具 -memray

Memray是一个由彭博社开发的、开源内存剖析器&#xff1b;开源一个多月&#xff0c;已经收获了超8.4k的star&#xff0c;是名副其实的明星项目。今天我们就给大家来推荐这款python内存分析神器。 ​ Memray可以跟踪python代码、本机扩展模块和python解释器本身中内存分配&#…

考完软考,有什么备考心得和学习经验可以分享吗?

我考过信息系统项目管理师&#xff0c;可以给你一些备考建议。这是软考高级资格考试的一门科目&#xff0c;考试包括三个部分。如果你觉得难度较大&#xff0c;可以先从系统集成考试开始&#xff0c;积累经验再去考高级科目。考试内容包括信息系统项目管理综合知识、信息系统项…

C语言中char、short、int、long各占多少字节

1byte 8bit 一个字节占8个二进制位 windows操作系统&#xff0c;32位机中&#xff0c; char&#xff1a; 1个字节 short&#xff1a; 2个字节 int&#xff1a; 4个字节 long&#xff1a; 4个字节 以下是windows操作系统&#xff0c;32位机下的代码测试结果&#xff08;3…

深入理解机器学习与极大似然之间的联系

似然函数&#xff1a;事件A的发生含着有许多其它事件的发生。所以我就把这些其它事件发生的联合概率来作为事件A的概率&#xff0c;也就是似然函数。数据类型的不同&#xff08;离散型和连续性&#xff09;就有不同的似然函数 极大似然极大似然估计方法&#xff08;Maximum Li…

MongoDB文档--基本安装-linux安装(mongodb环境搭建)-docker安装(挂载数据卷)-以及详细版本对比

阿丹&#xff1a; 前面了解了mongodb的一些基本概念。本节文章对安装mongodb进行讲解以及汇总。 官网教程如下&#xff1a; 安装 MongoDB - MongoDB-CN-Manual 版本特性 下面是各个版本的选择请在安装以及选择版本的时候参考一下&#xff1a; MongoDB 2.x 版本&#xff1a…

深入学习 Redis - 基于 Jedis 通过 Java 客户端操作 Redis

目录 一、Jedis 依赖 二、Java 客户端操控 redis 2.1、准备工作&#xff08;ssh 隧道&#xff09; 2.2、概要 2.2、string 2.3、hash 2.4、list 2.5、set 2.5、zset 一、Jedis 依赖 自己去 中央仓库 上面找. 二、Java 客户端操控 redis 2.1、准备工作&#xff08;ssh 隧…

51单片机(普中HC6800-EM3 V3.0)实验例程软件分析 实验二 LED闪烁

目录 前言 一、原理图及知识点介绍 二、代码分析 知识点四&#xff1a;delay(u16 i)这个函数为什么i1时&#xff0c;大约延时10us&#xff1f; 前言 已经是第二个实验了&#xff0c;上一个实验是点亮第一个LED灯&#xff0c;这个实验是LED的闪烁。 一、原理图及知识点介绍…

由红黑树到map/set

文章目录 一.map/set 的封装思路1.封装思路2.红黑树节点调整3.map 和 set 的定义4.仿函数 KeyOfValue5.map/set 的插入 二.map/set 迭代器实现1.迭代器的定义2.解引用运算符重载3.成员访问运算符重载4.(不)等于运算符重载5.begin() 与 end()6. 运算符重载7.-- 运算符重载8.[ ]下…

CSS学习记录(基础笔记)

CSS简介: CSS 指的是层叠样式表* (Cascading Style Sheets)&#xff0c;主要用于设置HTML页面的文字内容&#xff08;字体、大小、对齐方式&#xff09;&#xff0c;图片的外形&#xff08;边框&#xff09; CSS 描述了如何在屏幕、纸张或其他媒体上显示 HTML 元素 CSS 节省…

接口抓包,Fiddler抓包使用方法总结,入门到精通辅助实战...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 工作原理 Fiddle…

Docker网络模式详解

目录 Docker网络模式 一、Host模式 二、container模式 三、none模式 四、bridge模式 五、Overlay模式 Docker网络模式 安装Docker时会自动创建3个网络&#xff0c;可以使用docker network ls命令列出这些网络。 [rootdocker ~]# docker network ls 我们在使用docker run…

小程序服务器配置多大够用?

​  了解小程序服务器的大小和要求对于确保小程序的高效运行非常重要。下面将介绍小程序服务器的大小和要求&#xff0c;帮助您选择合适的服务器。 服务器费用 服务器费用因服务器类型、配置和带宽等因素而异。一般而言&#xff0c;小型小程序服务器的年费用在500元至2000元之…