JAVASE:OOP (面向对象)
mysql:持久化
html+CSS+jQuery+框架:视图
javaweb:独立开发MVC三层架构的网站,原始
ssm:框架,简化了我们的开发流程,配置也开始较为复杂
以上打包为war包,用tomcat 运行
Spring再简化:SpringBoot;微服务架构 打包为jar包,内嵌tomcat
服务越来越多:SpringCloud 来整理
是什么?
配置如何编写 yaml
自动装配原理【重要,面试谈】
继承web开发【业务的核心】
集成数据库【Druid】
分布式开发:Dubbo(RPC)+zookeeper【面试会问】
swagger:接口文档
任务调度
SpringSecurity【跟拦截器很像,但更简化 Shiro】
微服务
SpringCloud入门
Restful风格
Eureka
Ribbon
Feign
HyStrix
Zuul 路由网关
SpringCloud config 【操作git】
Spring是一个开源框架
Spring是为了解决企业级应用开发的复杂性而创建的,简化开发 【面试问】
为了降低Java开发的复杂性,Spring采用了以下4种关键策略:
1、基于POJO的轻量级和最小侵入性编程,所有东西都是bean;
2、通过IOC,依赖注入(DI)和面向接口实现松耦合;
3、基于切面(AOP)和惯例进行声明式编程;
4、通过切面和模版减少样式代码,RedisTemplate,xxxTemplate;
新服务架构:服务网格
简化开发,约定大于配置
java企业级开应用---->J2EE----->spring----->SpringBoot的过程
约定大于配置:maven,spring,springmvc,springboot
Spring Boot 以约定大于配置的核心思想,默认帮我们进行了很多设置,多数 Spring Boot 应用只需要很少的 Spring 配置。同时它集成了大量常用的第三方库配置(例如 Redis、MongoDB、Jpa、RabbitMQ、Quartz 等等),Spring Boot 应用中这些第三方库几乎可以零配置的开箱即用
程序=数据结构+算法(集合框架) 程序员
程序=面向对象+框架 码农
是一种架构的风格,要求在开发一个应用的时候,这个应用必须构建一系列小服务的组合;通过http的方式进行互通。
架构:MVC三层架构,MVVM 微服务架构
业务:service:userService =====》模块
软实力:聊天+举止+谈吐+见解
环境:jdk1.8 、maven、springboot最新版、idea
官方:提供了一个快速生成的网站,IDEA集成了这个网站
Spring Initializr 官方提供的创建
Group(群):com.p
Artifact(项目名):SpringBoot
点击加载依赖:选择spring Web依赖
选择jdk版本
最后点击下载,生成一个zip包解压到
用IDEA,import项目,然后下载依赖
选择 import project from external model 然后 选择maven
查看项目位置,然后下一步,然后选择jdk,下一步,最后查看项目名称和位置,点击结束
等待下载依赖包
可以把.mvn .giignore Help.md mvnw mvnw.cmd
删掉,就是一个熟悉的maven 项目
HelloSpringBootApplication
//本身就是spring的一个组件
//程序主入口,不能删
@SpringBootApplication
public class HelloSpringBootApplication {
//启动
public static void main(String[] args) {
SpringApplication.run(HelloSpringBootApplication.class, args);
}
}
application.properties
程序的核心配置文件
在test文件下的是单元测试
在HelloSpringBootApplication
的同级目录下创建controller包
//自动装配
//不走视图层,返回一个json
@RestController
public class HelloController {
//接口:http://localhost:8080/hello
//前端访问接口就行
@GetMapping("/hello")//gei请求
public String hello(){
//调用业务,接收前端的参数
return "hello SpringBoot";
}
}
在访问后得到一个hello springboot
pom.xml文件
<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.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.6.7version>
<relativePath/>
parent>
<groupId>com.pgroupId>
<artifactId>HelloSpringBootartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>HelloSpringBootname>
<description>Demo project for Spring Bootdescription>
<properties>
<java.version>1.8java.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
在右侧的maven中,选择Lifecycle 找到 package 双击 开始打包
执行: java -jar 项目名
在application.properties
中修改或添加
#更改项目的端口号
server.port=8081
Spring Boot banner在线生成工具,制作下载banner.txt,修改替换banner.txt文字实现自定义,个性化启动banner-bootschool.net
然后在resource下创建 banner.txt,将图片放进去,如果文件上有一个小小的角标,那么已经被识别了
选择Spring Initializr,选择默认Default,下一步
Group(群):com.p
Artifact(项目名):SpringBoot
type:maven project
Language:java
java Version:8
Description(项目描述):如:first springboot project
Package(包名): 如:com.p 下一步
可以选择依赖包 如:spring web 也可以不选
spring-boot-dependencies:核心依赖在父工程中
其中它主要是依赖一个父项目,主要是管理项目的资源过滤及插件!
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.2.5.RELEASEversion>
<relativePath/>
parent>
点进去,发现还有一个父依赖
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-dependenciesartifactId>
<version>2.2.5.RELEASEversion>
<relativePath>../../spring-boot-dependenciesrelativePath>
parent>
这里才是真正管理SpringBoot应用里面所有依赖版本的地方,SpringBoot的版本控制中心;
以后我们导入依赖默认是不需要写版本;但是如果导入的包没有在依赖中管理着就需要手动配置版本了
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starterartifactId>
dependency>
springboot-boot-starter-xxx:就是spring-boot的场景启动器
启动器:说白了就是Springboot的启动场景
如:spring-boot-starter-web
,就会自动导入web环境所有的依赖
springboot会将所有的功能场景,都变成一个个的启动器
如果要使用什么功能,只需要找到对应的启动器就可以了 starter
SpringBoot将所有的功能场景都抽取出来,做成一个个的starter (启动器),只需要在项目中引入这些starter即可,所有相关的依赖都会导入进来 , 我们要用什么功能就导入什么样的场景启动器即可 ;我们未来也可以自己自定义 starter;
//程序主入口
//SpringBootApplication: 标注这个类是一个springboot的应用
@SpringBootApplication
public class HelloSpringBootApplication {
public static void main(String[] args) {
//将springboot应用启动
SpringApplication.run(HelloSpringBootApplication.class, args);
}
}
@SpringBootConfiguration: SpringBoot的配置
@ConfigUration: spring配置类
@Component: 说明这也是一个spring的组件
@EnableAutoConfiguration:自动导入配置
@AutoConfigurationPackage: 自动配置包
@Import({AutoConfigurationImportPackages.Registrar.class})自动配置·包注册·
@Import({AutoConfigurationImportSelector.class}): 自动配置导入选择
//程序主入口
@SpringBootApplication
public class HelloSpringBootApplication {
//将springboot应用启动
//springApplication类
//run方法
public static void main(String[] args) {
SpringApplication.run(HelloSpringBootApplication.class, args);
}
}
如何自定一个主程序
将原先的删掉
@SpringBootApplication
public class diyApplication {
public static void main(String[] args){
}
}
SpringApplication
这个类主要做了以下四件事情
1、推断应用的类型是普通项目还是web项目
2、查找并加载所有可用初始化器,设置到initializers属性中
3、找到所有的应用程序监听器,设置到listeners属性中
4、推断并设置main方法的定义类,找到运行的主类
全面接管SpringMVC的配置
将原先的properties文件删除
application.yaml文件
server:
port: 8081 #中间有个空格 不然没有高亮
# k=v 普通的key-value
# 注入到我们的配置类中
name: zhangsan # yaml中
#对象
student:
name: zhangsan
age: 3
# 对象的行内写法
student: {name: zhangsan,age: 3}
# 数组
pets:
-cat
-dog
-pig
# 数组的行内写法
pets: [cat,dog,pig]
# properties只能保存键值对
name=zhangsan
student.name= zhangsan
student.age= 3
pojo类中Dog实体类
//原生的方式给属性赋值
//spring的组件
@Component
public class Dog {
@Value("旺财")
private String name;
@Value("3")
private Integer age;
}
person实体类
@Component
public class Person {
private String name;
private Integer age;
private Boolean happy;
private Date birth;
private Map<String,Object> maps;
private List<Object> lists;
private Dog dog;
}
测试类 springBoot
中的测试类
@SpringBootTest
class HelloSpringBootApplicationTests {
//自动装配
@Autowired
private Dog dog;
@Test
void contextLoads() {
System.out.println(dog);
}
}
结果为 Dog{name='旺财', age=3}
通过yaml来给属性赋值
person:
name: zhangsan
age: 3
happy: false
birth: 2020/11/02
maps: {k1: v1,k2: v2}
lists:
- code #注意空格
- music
- girl
dog:
name: 旺财
age: 3
@Component
@ConfigurationProperties(prefix = "person")//需要跟yaml中的绑定
public class Person {
private String name;
private Integer age;
private Boolean happy;
private Date birth;
private Map<String,Object> maps;
private List<Object> lists;
private Dog dog;
}
测试
@SpringBootTest
class HelloSpringBootApplicationTests {
//自动装配
//@Autowired
//private Dog dog;
@Autowired
private Person person;
@Test
void contextLoads() {
//System.out.println(dog);
System.out.println(person);
}
}
//结果为
//Person{name='zhangsan', age=3, happy=false, birth=Mon Nov 02 00:00:00 CST 2020, maps={k1=v1, k2=v2}, lists=[code, music, girl], dog=Dog{name='旺财', age=3}}
person:
name: zhangsan${random.uuid} #随机数id
age: ${random.int} #随机数
happy: false
birth: 2020/11/02
maps: {k1: v1,k2: v2}
hello: 你好
lists:
- code #注意空格
- music
- girl
dog:
name: ${person.hello: hello}旺财
#当hello不存在时 输出hello旺财,当hello存在时输出你好旺财
age: 3
diy.properties
name=zhangsan
@Component
@PropertySource(value = "classpath:diy.properties")
public class Person {
//SPEL表达式取出配置文件的值
@Value("${name}")
private String name;
private Integer age;
private Boolean happy;
private Date birth;
private Map<String,Object> maps;
private List<Object> lists;
private Dog dog;
}
@Validated //数据校验
public class Person {
@Email()//默认为空 需要导入依赖
//@Email(message = "邮箱格式不对")
private String name;
private Integer age;
private Boolean happy;
private Date birth;
private Map<String,Object> maps;
private List<Object> lists;
private Dog dog;
}
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-validationartifactId>
dependency>
限制 说明
@Null 限制只能为null
@NotNull 限制必须不为null
@AssertFalse 限制必须为false
@AssertTrue 限制必须为true
@DecimalMax(value) 限制必须为一个不大于指定值的数字
@DecimalMin(value) 限制必须为一个不小于指定值的数字
@Digits(integer,fraction) 限制必须为一个小数,且整数部分的位数不能超过integer,小数部分的位数不能超过fraction
@Future 限制必须是一个将来的日期
@Max(value) 限制必须为一个不大于指定值的数字
@Min(value) 限制必须为一个不小于指定值的数字
@Past 限制必须是一个过去的日期
@Pattern(value) 限制必须符合指定的正则表达式
@Size(max,min) 限制字符长度必须在min到max之间
@Past 验证注解的元素值(日期类型)比当前时间早
@NotEmpty 验证注解的元素值不为null且不为空(字符串长度不为0、集合大小不为0)
@NotBlank 验证注解的元素值不为空(不为null、去除首位空格后长度为0),不同于@NotEmpty,@NotBlank只应用于字符串且在比较时会去除字符串的空格
@Email 验证注解的元素值是Email,也可以通过正则表达式和flag指定自定义的email格式
生产环境路径application-dev.properties
server.port=8082
生产环境路径application-test.properties
server.port=8083
# spring的多环境配置:可以选择激活哪一个
# spring.profiles.active=dev
spring.profiles.active=test
#只需要填入 -后面的内容即可
使用yaml进行
server:
port: 8080
spring:
profiles:
active: dev
--- #使用---来分割
server:
port: 8082
spring:
profiles: dev
---
server:
port: 8082
spring:
profiles: test
jar:webapp
springboot 到底帮我们配置了什么?能不能进行修改?能修改哪些东西?能不能扩展?
xxxAutoConfiguraion
向容器中自动配置组件xxxProperties
:自动配置类,装配配置文件中自定义的一些内容要解决的问题:
Thymeleaf
在springboot,可以使用以下方式处理静态资源
webjars localhost:8080/webjars/
在resource目录下创建 public包、static包、resource 路径:localhost:8080/
自定义的需要在配置文件中配置 如在properties中
spring.mvc.static-path-pattern=/zhangsan/*
这样其他的资源就失效了
优先级:resource>static(默认)>public
在静态资源目录下放置index.html页面即可
public,static,resource,自定义静态资源目录下都可以
在templates
目录下的所有页面,只能通过controller
来跳转
图标也是放到静态资源目录下,favicon.ico 格式
只要需要使用Thymeleaf,只需要导入对应的依赖即可,将html放在templates目录下即可
需要导入Thymeleaf依赖
<dependency>
<groupId>org.thymeleafgroupId>
<artifactId>thymeleaf-spring5artifactId>
<version>3.0.11.RELEASEversion>
<scope>compilescope>
dependency>
<dependency>
<groupId>org.thymeleaf.extrasgroupId>
<artifactId>thymeleaf-extras-java8timeartifactId>
<version>3.0.4.RELEASEversion>
<scope>compilescope>
dependency>
创建testController
@Controller
public class testController {
@RequestMapping("/test")
public String test(Model model){
model.addAttribute("msg","helloSpringBoot");
return "test";
}
}
在templates
目录下创建test.html
注意:html使用Thymeleaf 需要添加标签
xmlns:th="http://www.thymeleaf.org"
DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div th:text="${msg}">div>
body>
html>
关闭模板引擎的缓存,在properties中配置
# 关闭模板引擎缓存
spring.thymeleaf.cache=false
遍历
@Controller
public class testController {
@RequestMapping("/test")
public String test(Model model){
model.addAttribute("users", Arrays.asList("1","2","3"));
return "test";
}
}
DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<h3 th:each="user:${users}" th:text="${user}">h3>
<h3 th:each="user:${users}">[[${user}]]h3>
body>
html>
th属性,常用th属性如下:
1)th:text:文本替换;
2)th:utext:支持html的文本替换。
3)th:value:属性赋值
4)th:each:遍历循环元素
5)th:if:判断条件,类似的还有th:unless,th:switch,th:case
6)th:insert:代码块引入,类似的还有th:replace,th:include,常用于公共代码块提取的场景
7)th:fragment:定义代码块,方便被th:insert引用
8)th:object:声明变量,一般和*{}一起配合使用,达到偷懒的效果。
9)th:attr:设置标签属性,多个属性可以用逗号分隔
2、标准表达式语法:
${...} 变量表达式,Variable Expressions 变量
@{...} 链接表式,Link URL Expressions 路径
#{...} 消息表达式,Message Expressions 国际化消息(中英文替换)
~{...} 代码块表达式,Fragment Expressions
*{...} 选择变量表达式,Selection Variable Expressions
~{...} 代码块表达式
支持两种语法结构
推荐:~{templatename::fragmentname}
支持:~{templatename::#id}
代码块表达式需要配合th属性(th:insert,th:replace,th:include)一起使用。
th:insert:将代码块片段整个插入到使用了th:insert的HTML标签中,
th:replace:将代码块片段整个替换使用了th:replace的HTML标签中,
th:include:将代码块片段包含的内容插入到使用了th:include的HTML标签中
如果diy一些定制化的功能,只需要写这个组件,然后将它交个springboot,springboot就会帮我们自动装配
创建新的config包 创建 MyMvcConfig
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
//ViewResolver 实现了视图解析器接口的类,就可以把他看做视图解析器
public ViewResolver myViewResolver(){
return new MyviewResolver();
}
//自定义了一个自己的视图解析器MyViewResolver
public static class MyviewResolver implements ViewResolver{
@Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
return null;
}
}
}
//如果扩展springmvc 官方建议我们这样去做
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
//视图跳转
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// http://localhost:8080/login
// 请求路径 访问网址
registry.addViewController("/login").setViewName("test");
}
}
注意:如果使用Thymeleaf首页链接需要用th托管
依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-jdbcartifactId>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
dependency>
application.yml
数据库连接配置文件
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8
driver-class-name: com.mysql.jdbc.Driver
数据库连接方式 测试类
@SpringBootTest
class SpringbootApplicationTests {
//springboot中封装的方法,方便连接数据库
@Autowired
DataSource dataSource;
@Test
void contextLoads() {
//查看一下默认的数据源
//class com.zaxxer.hikari.HikariDataSource
System.out.println(dataSource.getClass());
//获取数据库连接
try {
Connection con = dataSource.getConnection();
System.out.println(con);
//关闭
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
通过springboot中的模板来实现CRUD
package com.controller;
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 java.util.List;
import java.util.Map;
public class JdbcController {
//springBoot 封装的方法
@Autowired
JdbcTemplate jdbcTemplate;
//查询数据库的所有信息
//没有实体类,数据库中的数据可以通过 map来获取
@GetMapping("/uesrList")
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 into mybatis.user(id,name,pwd) values (4,'小明','123456')";
jdbcTemplate.update(sql);
return "add_ok";
}
@GetMapping("/updateUser/{id}")
public String updateUser(@PathVariable("id") int id){
String sql="update user set name=?,pwd=? where id+"+id;
//封装
Object[] object = new Object[2];
object[0]="小明2";
object[1]="zzzzz";
jdbcTemplate.update(sql,object);
return "update_ok";
}
@GetMapping("/deleteUser/{id}")
public String deleteUser(@PathVariable("id") int id){
String sql="delete from user where id=?";
jdbcTemplate.update(sql,id);
return "delete_ok";
}
}
依赖
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.1.21version>
dependency>
yaml配置
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8
driver-class-name: com.mysql.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource #加上这个就是选中Druid数据源
可以有的配置
spring:
datasource:
username: root
password: 123456
#?serverTimezone=UTC解决时区的报错
url: jdbc:mysql://localhost:3306/springboot?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
driver-class-name: com.mysql.cj.jdbc.Driver
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 # 需要导入log4j依赖
maxPoolPreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
测试
package com.p;
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 SpringbootApplicationTests {
@Autowired
DataSource dataSource;
@Test
void contextLoads() {
//查看一下默认的数据源
//class com.alibaba.druid.pool.DruidDataSource 这里已经变成阿里巴巴
System.out.println(dataSource.getClass());
//获取数据库连接
try {
Connection con = dataSource.getConnection();
System.out.println(con);
//关闭
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
绑定私有化属性
@Configuration
public class DruidConfig {
/*
将自定义的 Druid数据源添加到容器中,不再让 Spring Boot 自动创建
绑定全局配置文件中的 druid 数据源属性到 com.alibaba.druid.pool.DruidDataSource从而让它们生效
@ConfigurationProperties(prefix = "spring.datasource"):作用就是将 全局配置文件中
前缀为 spring.datasource的属性值注入到 com.alibaba.druid.pool.DruidDataSource 的同名参数中
*/
@ConfigurationProperties(prefix = "spring.datasource")
@Bean
public DataSource druidDataSource() {
return new DruidDataSource();
}
}
测试
@SpringBootTest
class SpringbootDataJdbcApplicationTests {
//DI注入数据源
@Autowired
DataSource dataSource;
@Test
public void contextLoads() throws SQLException {
//看一下默认数据源
System.out.println(dataSource.getClass());
//获得连接
Connection connection = dataSource.getConnection();
System.out.println(connection);
DruidDataSource druidDataSource = (DruidDataSource) dataSource;
System.out.println("druidDataSource 数据源最大连接数:" + druidDataSource.getMaxActive());
System.out.println("druidDataSource 数据源初始化连接数:" + druidDataSource.getInitialSize());
//关闭连接
connection.close();
}
}
配置Druid数据源监控
注意需要导入log4j的依赖
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
@Configuration
public class DruidConfig {
/*
将自定义的 Druid数据源添加到容器中,不再让 Spring Boot 自动创建
绑定全局配置文件中的 druid 数据源属性到 com.alibaba.druid.pool.DruidDataSource从而让它们生效
@ConfigurationProperties(prefix = "spring.datasource"):作用就是将 全局配置文件中
前缀为 spring.datasource的属性值注入到 com.alibaba.druid.pool.DruidDataSource 的同名参数中
*/
@ConfigurationProperties(prefix = "spring.datasource")
@Bean
public DataSource druidDataSource() {
return new DruidDataSource();
}
//配置 Druid 监控管理后台的Servlet;
//内置 Servlet 容器时没有web.xml文件,所以使用 Spring Boot 的注册 Servlet 方式
@Bean
public ServletRegistrationBean statViewServlet() {
ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
// 这些参数可以在 com.alibaba.druid.support.http.StatViewServlet
// 的父类 com.alibaba.druid.support.http.ResourceServlet 中找到
Map<String, String> initParams = new HashMap<>();
initParams.put("loginUsername", "admin"); //后台管理界面的登录账号
initParams.put("loginPassword", "123456"); //后台管理界面的登录密码
//后台允许谁可以访问
//initParams.put("allow", "localhost"):表示只有本机可以访问
//initParams.put("allow", ""):为空或者为null时,表示允许所有访问
initParams.put("allow", "");
//deny:Druid 后台拒绝谁访问
//initParams.put("kuangshen", "192.168.1.20");表示禁止此ip访问
//设置初始化参数
bean.setInitParameters(initParams);
return bean;
}
}
访问http://localhost:8080/druid/login.html
配置 Druid web 监控 filter 过滤器
@Configuration
public class DruidConfig {
/*
将自定义的 Druid数据源添加到容器中,不再让 Spring Boot 自动创建
绑定全局配置文件中的 druid 数据源属性到 com.alibaba.druid.pool.DruidDataSource从而让它们生效
@ConfigurationProperties(prefix = "spring.datasource"):作用就是将 全局配置文件中
前缀为 spring.datasource的属性值注入到 com.alibaba.druid.pool.DruidDataSource 的同名参数中
*/
@ConfigurationProperties(prefix = "spring.datasource")
@Bean
public DataSource druidDataSource() {
return new DruidDataSource();
}
//配置 Druid 监控 之 web 监控的 filter
//WebStatFilter:用于配置Web和Druid数据源之间的管理关联监控统计
@Bean
public FilterRegistrationBean webStatFilter() {
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new WebStatFilter());
//exclusions:设置哪些请求进行过滤排除掉,从而不进行统计
Map<String, String> initParams = new HashMap<>();
initParams.put("exclusions", "*.js,*.css,/druid/*,/jdbc/*");
bean.setInitParameters(initParams);
//"/*" 表示过滤所有请求
bean.setUrlPatterns(Arrays.asList("/*"));
return bean;
}
}
依赖
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>2.1.1version>
dependency>
在properties配置
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/rongma4?useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=123456
# mybatis配置
#起别名
mybatis.type-aliases-package=com.p.pojo
# 绑定mapper.xml文件 在resources目录下创建mybatis/mapper/UserMapper.xml
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
接口
@Mapper //注意 表示本类是一个 MyBatis 的 Mapper
@Repository //表示被spring托管
public interface UserMapper {
//登录
List<Users> userLogin(Map map);
}
Mapper 在在resources目录下创建mybatis/mapper/UserMapper.xml
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.p.mapper.UserMapper">
<select id="userLogin" parameterType="map" resultType="users">
select * from rongma4.user where zh=#{zh} and pass=#{pass};
select>
mapper>
测试
@Autowired
private UserMapper userdao;
@Test
void contextLoads() throws SQLException {
HashMap map = new HashMap();
map.put("zh","123");
map.put("pass","134");
List<Users> usersList = userdao.userLogin(map);
if (usersList.size()>0){
System.out.println("true");
}else {
System.out.println("false");
}
}
测试成功可以在controller中使用
依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-securityartifactId>
dependency>
在web开发中,安全第一位,过滤器,拦截器
功能性需求:否
做网站:安全应该在什么时候考虑 设计之初
shiro
、SpringSecurity:很像,除了类不一样,名字不一样
认证,授权(VIP1,VIP2,VIP3)
权限有哪些
Spring Security 是针对Spring项目的安全框架,也是Spring Boot底层安全模块默认的技术选型,他可以实现强大的Web安全控制,对于安全控制,我们仅需要引入 spring-boot-starter-security 模块,进行少量的配置,即可实现强大的安全管理!
记住几个类:
Spring Security的两个主要目标是 “认证” 和 “授权”(访问控制)。
“认证”(Authentication)
身份验证是关于验证您的凭据,如用户名/用户ID和密码,以验证您的身份。
身份验证通常通过用户名和密码完成,有时与身份验证因素结合使用。
“授权” (Authorization)
授权发生在系统成功验证您的身份后,最终会授予您访问资源(如信息,文件,数据库,资金,位置,几乎任何内容)的完全权限。
这个概念是通用的,而不是只在Spring Security 中存在。
编写基础的配置类config
package com.p.config;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@EnableWebSecurity // 开启WebSecurity模式
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//授权
@Override
protected void configure(HttpSecurity http) throws Exception {
// 定制请求的授权规则
// 首页所有人可以访问
http.authorizeRequests().antMatchers("/").permitAll()
//只要权限是vip1的可以访问
.antMatchers("/level1/**").hasRole("vip1")
.antMatchers("/level2/**").hasRole("vip2")
.antMatchers("/level3/**").hasRole("vip3");
// 开启自动配置的登录功能
// /login 请求来到登录页
// /login?error 重定向到这里表示登录失败
//如果没有写/login路径,则返回一个默认的登录页面
http.formLogin();
}
//定义认证规则
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//在jdbc获取定义认证规则
auth.jdbcAuthentication()
//在内存中定义,也可以在jdbc中去拿....
auth.inMemoryAuthentication()
.withUser("kuangshen").password("123456").roles("vip2","vip3")
.and()
.withUser("root").password("123456").roles("vip1","vip2","vip3")
.and()
.withUser("guest").password("123456").roles("vip1","vip2");
}
}
在认证时需要对密码进行加密
//定义认证规则
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//在内存中定义,也可以在jdbc中去拿....
//Spring security 5.0中新增了多种加密方式,也改变了密码的格式。
//要想我们的项目还能够正常登陆,需要修改一下configure中的代码。我们要将前端传过来的密码进行某种方式加密
//spring security 官方推荐的是使用bcrypt加密方式。
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("kuangshen").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2","vip3")
.and()
.withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3")
.and()
.withUser("guest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2");
}
JDBC认证
@Autowired //获取数据源
private DataSource dataSource;
//认证
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource)
.withDefaultSchema()
.withUser(users.username("name")).password("password").roles("vip1");
注销功能
//定制请求的授权规则
@Override
protected void configure(HttpSecurity http) throws Exception {
//....
//开启自动配置的注销的功能
// /logout 注销请求,跳到默认的路径
http.logout();
//如何注销后跳到首页
http.logout().logoutSuccessUrl("/index");
}
前端路径
<a href="/logout">a> 这是默认的注销的路径
自定义登录页面
//定制登录页面 登录页面的访问路径 自定义前端中的name属性,默认是username
http.formLogin().ioginPage("/toLogin").usernameParameter("user")
.passwordParameter("pwd")
.loginProcessingUrl("/login")//访问的页面
//防止网站工具
http.csrf().disable();
//注销到自定义路径
http.logout().logoutSuccessUrl("/");
前端
<form action="/tologin" method="post"> 登录页面的访问路径 必须是post请求
用户名:<input type="text" name="user" >
密码<input type="text" name="pwd">
<input type="check" name="remember">
form>
记住我功能
//默认的记住我
http.remeberMe();
//自定义记住我功能 获取前端的参数
http.remeberMe().rememberMeParameter("remember")
1、Apache Shiro是一个java的安全(权限)框架
2、Shiro可以非常容易的开发出足够好的应用,其不仅可以用在javaSE环境中,可以用在JavaEE中
3、Shiro可以完成,认证,授权,加密,会话管理,Web集成,缓存等
Authentication:身份认证/登录,验证用户是不是拥有相应的身份
Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能进行什么操作,如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限
Session Management:会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通JavaSE环境,也可以是Web 环境的
Cryptography:加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储
Web Support:Web 支持,可以非常容易的集成到Web 环境
Caching:缓存,比如用户登录后,其用户信息、拥有的角色/权限不必每次去查,这样可以提高效率
Concurrency:Shiro支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去
Testing:提供测试支持
“Run As”:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问
Remember Me:记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了
步骤:
<dependency>
<groupId>org.apache.shirogroupId>
<artifactId>shiro-coreartifactId>
<version>1.5.3version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>jcl-over-slf4jartifactId>
<version>1.7.26version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-log4j12artifactId>
<version>1.7.26version>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
log4j.properties
log4j.rootLogger=INFO, stdout
log4j.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=WARNS
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
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Simple Quickstart application showing how to use Shiro's API.
* 简单入门Shiro使用API
*
* @since 0.9 RC2
*/
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);
// 获取当前的用户对象 Subject
Subject currentUser = SecurityUtils.getSubject();
//通过当前用户拿到Shiro的Session 可以脱离web存值取值
Session session = currentUser.getSession();
session.setAttribute("someKey", "aValue");
String value = (String) session.getAttribute("someKey");
if (value.equals("aValue")) {
log.info("Retrieved the correct value! [" + value + "]");
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?
}
}
//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);
}
}
当打印出一些日志文件,则说明成功。
Spring Secutrry都有~(只是换了个名字)
// 获取当前的用户对象 Subject
Subject currentUser = SecurityUtils.getSubject();
//拿到subject的session
Session session = currentUser.getSession();
//判断当前用户是否被认证
currentUser.isAuthenticated()
//获取当前用户的认证
currentUser.getPrincipal()
//获取当前用户拥有什么角色
currentUser.hasRole("schwartz")
//用户可以获得的权限
currentUser.isPermitted("lightsaber:wield")
//注销
currentUser.logout();
1、搭建SpringBoot框架
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-thymeleafartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
<exclusions>
<exclusion>
<groupId>org.junit.vintagegroupId>
<artifactId>junit-vintage-engineartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.apache.shirogroupId>
<artifactId>shiro-springartifactId>
<version>1.5.3version>
dependency>
dependencies>
@Controller
public class MyController {
@RequestMapping({"/","/index"})
public String toIndex(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";
}
}
index.html
DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首页title>
head>
<body>
<div>
<h1>首页h1>
<p th:text="${msg}">p>
<hr>
<a th:href="@{/user/add}">adda> | <a th:href="@{/user/update}">updatea>
div>
body>
html>
add.html
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<h1>addh1>
body>
html>
update.html
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<h1>updateh1>
body>
html>
@Configuration
public class ShiroConfig {
//3. shiroFilterFactoryBean
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
// 设置安全管理器
bean.setSecurityManager(defaultWebSecurityManager);
return bean;
}
//2. DefaultWebSecurityManager
@Bean //通过spring来绑定配置类
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 关联userRealm
securityManager.setRealm(userRealm);
return securityManager;
}
//1. 创建realm对象,需要自定义类
@Bean
public UserRealm userRealm() {
return new UserRealm();
}
}
UserRealm
//自定义的UserRealm
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("执行了=>认证doGetAuthorizationInfo");
return null;
}
}
ShiroConfig
/*在ShiroConfig中的getShiroFilterFactoryBean方法中添加如下配置
anon: 无需认证就可以访问
authc: 必须认证了才能访问
user: 必须拥有记住我功能才能用
perms: 拥有对某个资源的权限才能访问
role: 拥有某个角色权限
*/
Map<String, String> filterMap = new LinkedHashMap<>();
filterMap.put("/user/add","authc");
filterMap.put("/user/update","authc");
bean.setFilterChainDefinitionMap(filterMap);
需要再写个登录页面
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录页面title>
head>
<body>
<h1>登录h1>
<hr>
<form action="">
<p>用户名:<input type="text" name="username">p>
<p>密码:<input type="text" name="password">p>
<p>密码:<input type="submit">p>
form>
body>
html>
在controller中
@RequestMapping("/toLogin")
public String toLogin() {
return "login";
}
在ShiroConfig
中的getShiroFilterFactoryBean
方法中添加如下配置
//设置登录的请求
bean.setLoginUrl("/toLogin");
整体代码ShrioConfig
@Configuration
public class ShiroConfig {
//3. shiroFilterFactoryBean
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
// 设置安全管理器
bean.setSecurityManager(defaultWebSecurityManager);
/*
anon:无序认证就可以访问
authc:必须认证了才能访问
user:必须拥有,记住我,功能才能用
perms:拥有对某个资源的权限才能访问
role:拥有某个角色权限才能访问
*/
//拦截
Map<String, String> filterMap = new LinkedHashMap<>();
/*filterMap.put("/user/add","authc");user下add必须认证了才能访问
filterMap.put("/user/update","authc");*/
filterMap.put("/user/*","authc");//通配符
bean.setFilterChainDefinitionMap(filterMap);
//设置登录的请求
bean.setLoginUrl("/toLogin");
return bean;
}
//2. DefaultWebSecurityManager
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 关联userRealm
securityManager.setRealm(userRealm);
return securityManager;
}
//1. 创建realm对象,需要自定义类
@Bean
public UserRealm userRealm() {
return new UserRealm();
}
}
Controller
package com.p.controller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class ShiroController {
@RequestMapping("/toLogin")
public String toLogin() {
return "login";
}
@RequestMapping("/user/add")
public String add() {
return "user/add";
}
@RequestMapping("/user/update")
public String update() {
return "user/update";
}
@RequestMapping("/")
public String index() {
return "index2";
}
}
登录界面
DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>登录页面title>
head>
<body>
<h1>登录h1>
<hr>
<p th:text="${msg}" style="color: red">p>
<form th:action="@{/login}" method="post">
<p>用户名:<input type="text" name="username">p>
<p>密码:<input type="text" name="password">p>
<p>密码:<input type="submit">p>
form>
body>
html>
1、获取前端的输入的数据
//前端接收用户名和密码
@RequestMapping("/login")
public String login(String username, String password, Model model){
//获取当前用户
Subject subject = SecurityUtils.getSubject();
//封装用户的登录数据
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
//手动设置异常
try{
//执行登录方法,如果没有异常就说明ok了
subject.login(token);
//登录成功返回到首页
return "index2";
//下面是错误信息
}catch (UnknownAccountException e){
//用户名不存在
model.addAttribute("msg","用户名错误");
return "login";
}catch (IncorrectCredentialsException e){
model.addAttribute("msg","密码错误");
return "login";
}
}
2、UserRealm
进行认证操作
package com.p.config;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
//自定义的UserRealm
public class UserRealm extends AuthorizingRealm {
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行了=>授权doGetAuthorizationInfo");
return null;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("执行了=>认证doGetAuthorizationInfo");
//从controller中获取了被封装的username和password 封装成token
//设置虚拟数据 可以从数据库中获取
String name = "root";
String password = "root";
UsernamePasswordToken userToken = (UsernamePasswordToken)token;
//进行判断
if (!userToken.getUsername().equals(name)){
return null;//抛出异常 UnknownAccountException
}
//密码认证,shrio做
return new SimpleAuthenticationInfo("",password,"");
}
}
环境搭建
@Mapper
@Repository
public interface UserMapper {
public User queryUserByName(String name);
}
<mapper namespace="com.p.mapper.UserMapper">
<select id="queryUserByName" resultType="com.p.pojo.User" parameterType="string">
select * from mybatis.user where name = #{name};
select>
mapper>
public interface UserService {//接口可以不用加Service注解
public User queryUserByName(String name);
}
@Service
public class UserServiceImpl implements UserService {
@Autowired
UserMapper userMapper;
@Override
public User queryUserByName(String name) {
return userMapper.queryUserByName(name);
}
}
在UserRealm
中连接service层的逻辑
package com.p.config;
import com.p.pojo.User;
import com.p.service.UserService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
//自定义的UserRealm
public class UserRealm extends AuthorizingRealm {
//自动扫包到Uservice
@Autowired
UserService userService;
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行了=>授权doGetAuthorizationInfo");
return null;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("执行了=>认证doGetAuthorizationInfo");
//从controller中获取了被封装的username和password 封装成token
/* //设置虚拟数据 可以从数据库中获取
String name = "root";
String password = "root";*/
UsernamePasswordToken userToken = (UsernamePasswordToken)token;
//连接真实数据库,从controller获取到的封装数据,get到name
User user = userService.queryUserByName(userToken.getUsername());
if (user==null) {//进行判断
return null;//爆出异常,没有这个人
}
//可以加密,MD5加密
//密码认证,shrio做 密码加密了
return new SimpleAuthenticationInfo("",user.getPwd(),"");
}
}
设置没有权限的用户
package com.p.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;
import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
//3. shiroFilterFactoryBean
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
// 设置安全管理器
bean.setSecurityManager(defaultWebSecurityManager);
/*
anon:无序认证就可以访问
authc:必须认证了才能访问
user:必须拥有,记住我,功能才能用
perms:拥有对某个资源的权限才能访问
role:拥有某个角色权限才能访问
*/
Map<String, String> filterMap = new LinkedHashMap<>();
/*filterMap.put("/user/add","authc");
filterMap.put("/user/update","authc");*/
//授权 ,正常情况下,没有授权会跳转到未授权页面
// 必须拥有add权限才能访问该页面
filterMap.put("/user/add","perms[user:add]");
//设置未授权的请求页面
bean.setUnauthorizedUrl("/noauth");
filterMap.put("/user/*","authc");
bean.setFilterChainDefinitionMap(filterMap);
bean.setLoginUrl("/toLogin");
return bean;
}
}
未授权的请求页面
//未授权跳转
@RequestMapping("/noauth")
@ResponseBody
public String unauthorized(){
return "未经授权,禁止访问";
}
通过数据库中对用户数据表的权限
实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private int id;
private String name;
private String pwd;
private String auth;//用户权限
}
package com.p.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;
import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
//3. shiroFilterFactoryBean
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
// 设置安全管理器
bean.setSecurityManager(defaultWebSecurityManager);
/*
anon:无序认证就可以访问
authc:必须认证了才能访问
user:必须拥有,记住我,功能才能用
perms:拥有对某个资源的权限才能访问
role:拥有某个角色权限才能访问
*/
Map<String, String> filterMap = new LinkedHashMap<>();
/*filterMap.put("/user/add","authc");
filterMap.put("/user/update","authc");*/
//主要是这里
//设置页面必须有什么权限才能访问
//授权 ,正常情况下,没有授权会跳转到未授权页面
// 必须拥有add权限才能访问
filterMap.put("/user/add","perms[user]");
filterMap.put("/user/update","perms[admin]");
//设置未授权的请求页面
bean.setUnauthorizedUrl("/noauth");
//主要是这里
filterMap.put("/user/*","authc");
bean.setFilterChainDefinitionMap(filterMap);
bean.setLoginUrl("/toLogin");
return bean;
}
//2. DefaultWebSecurityManager
@Bean //通过spring来绑定配置类
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 关联userRealm
securityManager.setRealm(userRealm);
return securityManager;
}
//1. 创建realm对象,需要自定义类
@Bean
public UserRealm userRealm() {
return new UserRealm();
}
}
package com.p.config;
import com.p.pojo.User;
import com.p.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
//自定义的UserRealm
public class UserRealm extends AuthorizingRealm {
//自动扫包到Uservice
@Autowired
UserService userService;
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行了=>授权doGetAuthorizationInfo");
//通过这里对user的授权
//授权 SimpleAuthenticationInfo 【认证】 注意别搞混了
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); //授权
//添加一个权限
/*info.addStringPermission("user:add");*/
//通过下面的new SimpleAuthenticationInfo(user,user.getPwd(),""); 传值
Subject subject = SecurityUtils.getSubject();
User principal = (User) subject.getPrincipal();//拿到user对象
//通过数据库中user对象中的字段获取权限
//设置当前用户的权限 数据库中获取
info.addStringPermission(principal.getAuth());//用户权限 数据库中字段
return info;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("执行了=>认证doGetAuthorizationInfo");
//从controller中获取了被封装的username和password 封装成token
/* //设置虚拟数据 可以从数据库中获取
String name = "root";
String password = "root";*/
UsernamePasswordToken userToken = (UsernamePasswordToken)token;
//连接真实数据库,从controller获取到的封装数据,get到name
User user = userService.queryUserByName(userToken.getUsername());
if (user==null) {//进行判断
return null;//爆出异常,没有这个人
}
//可以加密,MD5加密
//密码认证,shrio做 密码加密了 修改为user上面可以就收
// 【可以让SecurityUtils.getSubject();获取到user对象】
return new SimpleAuthenticationInfo(【这里进行了修改】user,user.getPwd(),"");
}
}
thymlef
依赖
<dependency>
<groupId>com.github.theborakompanionigroupId>
<artifactId>thymeleaf-extras-shiroartifactId>
<version>2.0.0version>
dependency>
需要进行配置
在ShiroConifg
中配置
package com.p.config;
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
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;
import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
//3. shiroFilterFactoryBean
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
// 设置安全管理器
bean.setSecurityManager(defaultWebSecurityManager);
/*
anon:无序认证就可以访问
authc:必须认证了才能访问
user:必须拥有,记住我,功能才能用
perms:拥有对某个资源的权限才能访问
role:拥有某个角色权限才能访问
*/
Map<String, String> filterMap = new LinkedHashMap<>();
/*filterMap.put("/user/add","authc");
filterMap.put("/user/update","authc");*/
//授权 ,正常情况下,没有授权会跳转到未授权页面
// 必须拥有add权限才能访问
filterMap.put("/user/add","perms[user]");
filterMap.put("/user/update","perms[admin]");
//设置未授权的请求页面
bean.setUnauthorizedUrl("/noauth");
filterMap.put("/user/*","authc");
bean.setFilterChainDefinitionMap(filterMap);
bean.setLoginUrl("/toLogin");
return bean;
}
//2. DefaultWebSecurityManager
@Bean //通过spring来绑定配置类
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 关联userRealm
securityManager.setRealm(userRealm);
return securityManager;
}
//1. 创建realm对象,需要自定义类
@Bean
public UserRealm userRealm() {
return new UserRealm();
}
/*
-------------------------------------------------------------
*/
//整合ShiroDialect:用来整合 shiro thymlef
@Bean
public ShiroDialect getShiroDialect(){
return new ShiroDialect();
}
}
在thymlef
中加入Shiro标签
xmlns:shiro="http://www.pollix.at/thymeleaf/shiro"
主界面
DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
>
<head>
<meta charset="UTF-8">
<title>首页title>
head>
<body>
<div>
<h1>首页h1>
<div th:if="${session.user==null}">
<a th:href="@{/toLogin}">登录a>
div>
<hr>
<div shiro:hasPermission="user">
<a th:href="@{/user/add}">adda>
div>
<div shiro:hasPermission="admin">
<a th:href="@{/user/update}">updatea>
div>
div>
body>
html>
设置session值在 UserRealm
中配置也行
package com.p.config;
//自定义的UserRealm
public class UserRealm extends AuthorizingRealm {
//自动扫包到Uservice
@Autowired
UserService userService;
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行了=>授权doGetAuthorizationInfo");
//授权 SimpleAuthenticationInfo 【认证】 注意别搞混了
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); //授权
//添加一个权限
/*info.addStringPermission("user:add");*/
//通过下面的new SimpleAuthenticationInfo(user,user.getPwd(),""); 传值
Subject subject = SecurityUtils.getSubject();
User principal = (User) subject.getPrincipal();//拿到user对象
//通过数据库中user对象中的字段获取权限
//设置当前用户的权限 数据库中获取
info.addStringPermission(principal.getAuth());//用户权限 数据库中字段
return info;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("执行了=>认证doGetAuthorizationInfo");
//从controller中获取了被封装的username和password 封装成token
/* //设置虚拟数据 可以从数据库中获取
String name = "root";
String password = "root";*/
UsernamePasswordToken userToken = (UsernamePasswordToken)token;
//连接真实数据库,从controller获取到的封装数据,get到name
User user = userService.queryUserByName(userToken.getUsername());
if (user==null) {//进行判断
return null;//爆出异常,没有这个人
}
//设置的session ****************************
//设置session
Subject subject = SecurityUtils.getSubject();
Session session = subject.getSession();
session.setAttribute("user",user);
//可以加密,MD5加密
//密码认证,shrio做 密码加密了 修改为user上面可以就收
return new SimpleAuthenticationInfo(user,user.getPwd(),"");
}
}
学习目标:
号称世界上最流行的API框架
RestFul API 文档在线自动生成工具===》API文档与API定义同步更新
直接运行,可以在线测试API接口
支持多种语言(java,PHP…)
官网: API Documentation & Design Tools for Teams | Swagger
在项目中使用需要springbox
1、 新建springboot–web项目
2、依赖
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.5.5version>
<relativePath/>
parent>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger2artifactId>
<version>2.9.2version>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger-uiartifactId>
<version>2.9.2version>
dependency>
3、编写一个Hello工程
4、配置Swagger===》Config
@Configuration
@EnableSwagger2 //开启Swagger2
public class SwaggerConfig {
}
5、测试
访问路径 http://localhost:8080/swagger-ui.html
Swagger的bean实例Docket
package com.p.HelloSpringBoot.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.ArrayList;
@Configuration
@EnableSwagger2
public class SwaggerConfig {
//配置了swagger的Docket 修改默认配置
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2).
apiInfo(apiInfo());
}
//配置swagger信息 = apiInfo
/*
public static final ApiInfo DEFAULT;
private final String version; 版本信息
private final String title; 标题
private final String description; 描述
private final String termsOfServiceUrl; 服务组的路径
private final String license; 开源版本号
private final String licenseUrl;
private final Contact contact;
private final List vendorExtensions;
*/
private ApiInfo apiInfo(){
Contact contact = new Contact("pyh","http://8.131.94.43:8080//Boke/BokeList","[email protected]");
return new ApiInfo(
"pyh的SwaggerApi"//标题
,"描述"
,"v1.0"//版本号
,"http://8.131.94.43:8080//Boke/BokeList"//服务组的路径放个自己博客路径
,contact
,"Apache 2.0"
,"http://www.apache.org/licenses/LICENSE-2.0",
new ArrayList()
);
}
}
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2).
apiInfo(apiInfo())
//以下的是一个链式,其他方法需要在这个上面标注
.select()
//RequestHandlerSelectors ,配置要扫描接口的方式
//basePackage指定要扫描的包
//any()扫描全部
//none()不扫描
//withClassAnnotation(RestController.class)扫描类上的注解 参数是一个注解的反射对象 扫描有RestController注解的类
//withMethodAnnotation(RestController.class) 扫描方法上的注解 扫描有RestController注解的方法
.apis(RequestHandlerSelectors.basePackage("com.p.HelloSpringBoot.controller"))
/*.apis(RequestHandlerSelectors.any())*/
//paths 过滤什么路径
//ant() 过滤指定包下的
.paths(PathSelectors.ant("/p/**"))
.build();
}
.enable(false) 关闭Swagger
是否启动Swagger,如果为false,则Swagger不能在浏览器中访问
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2).
apiInfo(apiInfo())
.enable(false)//注意是在select上面标注,
//以下的是一个链式,其他方法需要在这个上面标注
.select()
.apis(RequestHandlerSelectors.basePackage("com.p.HelloSpringBoot.controller"))
.build();
}
只希望Swagger在生产环境中使用,在发布的时候不使用
-判断是不是生产环境
-注入enable(falg)
创建生产环境application-dev.properties
server.port=8081
创建发布环境application-pro.properties
server.port=8081
总配置环境application.properties
spring.profiles.active=dev
config中配置
@Bean
public Docket docket(Environment environment){
//设置要设置的Swagger环境
Profiles profiles = Profiles.of("dev","test");
//获取项目的环境
//通过environment.acceptsProfiles 判断是否处在自己设定的环境中
boolean flag = environment.acceptsProfiles(profiles);
return new Docket(DocumentationType.SWAGGER_2).
apiInfo(apiInfo())
.enable(flag)//判断是否处于生产环境【注意端口号】
.select()
.apis(RequestHandlerSelectors.basePackage("com.p.HelloSpringBoot.controller"))
.build();
}
.groupName("名字分组")
//多个Docket即可
public Docket docket1(){
return new Docket(DocumentationType.SWAGGER_2).groupName("A");
}
public Docket docket2(){
return new Docket(DocumentationType.SWAGGER_2).groupName("B");
}
在实体类上使用注解配置文档
//@Api("注释")
@ApiModel("用户类")
public class User {
@ApiModelProperty("用户名")
public String name;
@ApiModelProperty("密码")
public String pwd;
}
当控制类中写有该实体类方法就会显示
@RequestMapping("/hello2")
public User hello2(Model model){
return new User();
}
控制类方法上加入
@Api(tags = "控制类上的文档注释")
@Controller
public class testController {
//在方法中注释文档
@ApiOperation("hello方法文档")
@RequestMapping("/hello3")
public String hello3(Model model,@ApiParam("参数文档") String name){
return "hello"+name;
}
}
总结:
【注意点】在正式发布时候,关闭Swagger,而且省内存
1、创建service
@Service
public class AsyncService {
@Async//加上这个注解后,不会等待3s再出结果,而是直接出结果,再等3s 处理结果
//还需要在启动类中配置
public void Async(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("数据正在处理");
}
}
2、在主程序入口加上配置
//程序主入口
@EnableAsync//自动开启异步任务
@SpringBootApplication
public class HelloSpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(HelloSpringBootApplication.class, args);
}
}
3、controller中调用service方法
@RequestMapping("/hello4")
public String hello4(){
asyncService.Async();
return "ok"; //直接出结果,不去等待3s
}
项目开发中经常需要执行一些定时任务,比如需要在每天凌晨的时候,分析一次前一天的日志信息,Spring为我们提供了异步执行任务调度的方式,提供了两个接口。
TaskExecutor接口 任务调度者
TaskScheduler接口 任务执行者
在主程序入口处写
@EnableScheduling 开启定时功能的注解
@Scheduled 什么时候执行
Cron 表达式,可以在网上找表达式
步骤:
1、在主程序中开启定时功能的注解
//程序主入口
@SpringBootApplication
@EnableScheduling //开启定时功能的注解
public class HelloSpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(HelloSpringBootApplication.class, args);
}
}
2、编写要定时执行的任务
package com.p.HelloSpringBoot.service;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
@Service
public class ScheduledService {
//在一个指定的时间执行这个方法
//cron表达式
// 秒 分时日月 周几
/*@Scheduled(cron = "0 * * * * 0-7")*/
/*
0 28 9 * * ? 每天的9.28分0秒 执行一次
30 0/5 10,18 * * ? 每天10点和18点,每隔分钟执行一次
0 15 10 L * ? 每月最后一日的上午10:15触发
*/
@Scheduled(cron = "0 28 9 * * ?") // ?表示不确定是星期几
public void hello(){
System.out.println("hello,你被执行了");
}
}
依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-mailartifactId>
dependency>
在application.properties
中配置
[email protected]
# 在QQ中开启POP3服务
spring.mail.password=ioscscziprzabebb
spring.mail.host=smtp.qq.com
# 开启加密验证
spring.mail.properties.mail.smtp.ssl.enable=true
测试中使用 简单的邮件
package com.p.HelloSpringBoot;
import com.p.HelloSpringBoot.pojo.Dog;
import com.p.HelloSpringBoot.pojo.Person;
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;
import org.springframework.stereotype.Component;
@SpringBootTest
class HelloSpringBootApplicationTests {
@Autowired
JavaMailSenderImpl mailSender;
@Test
void contextLoads() {
SimpleMailMessage mailMessage = new SimpleMailMessage();
mailMessage.setSubject("你好"); //邮箱标题
mailMessage.setText("文章内容"); //文章内容
mailMessage.setTo("[email protected]");
mailMessage.setFrom("[email protected]");
mailSender.send(mailMessage);
}
}
//一个复杂的邮箱
void contextLoads2() {
//一个复杂的邮件
MimeMessage mimeMessage = mailSender.createMimeMessage();
//组装
try {
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
//正文
helper.setSubject("你好");
//将文本转化为html
helper.setText("验证码
",true);
//附件
helper.addAttachment("1.jpg",new File("文件路径"));
//发送给哪个邮箱
helper.setTo("[email protected]");
//谁发送的邮箱,必须是邮箱地址
helper.setFrom("[email protected]");
mailSender.send(mimeMessage);
} catch (MessagingException e) {
e.printStackTrace();
}
}
分布式系统是若干独立计算机的集合,这些计算机对于用户来说就像单个相关系统。
分布式系统是由一组通过网络进行通信、为了完成共同的任务而协调工作的计算机节点组成的系统。分布式系统的出现是为了用廉价的、普通的机器完成单个计算机无法完成的计算、存储任务。其目的是利用更多的机器,处理更多的数据。
随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,急需一个治理系统确保架构有条不紊的演进。
RPC【Remote Procedure Call】是指远程过程调用,是一种进程间通信方式,他是一种技术的思想,而不是规范。它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数,而不用程序员显式编码这个远程调用的细节。即程序员无论是调用本地的还是远程的函数,本质上编写的调用代码基本相同。
RPC两个核心模块:通讯,序列化。
序列化: 数据传输转换
zookeeper:注册中心
Dubbo-admin:是一个监控管理后台,查看我们注册了哪些服务,哪些服务被消费了
Dubbo:jar包
步骤:
前提:zookeeper服务已开启
1、提供者服务
1、导入依赖
2、配置注册中心的地址,以及服务发现名,和要扫描的包
3、在想要被注册的服务上门-增加一个注册@Service 【Dubbo的包】
2、消费者如何消费
1、导入依赖
2、配置注册中心的地址,配置自己的服务名
3、从远程注入服务 @Reference