数据中台技术

此项目不涉及高并发,所有没有springcloud的相关内容。

利用Springboot 搭建外部服务。
利用Mybatis及Mybatis-plus操作MySQL数据库。
从Hive中提取需要的元数据。
从 HDFS中提取相关信息。
从DolphinScheduler 的任务信息中提取相关信息。

3.1.1 什么是Web服务
Web服务(http服务),接收网页或者App应用发起的http请求,然后通过程序进行处理、计算、查询、存储等,再将结果返回给页面或App应用。
web服务

在Springboot框架之前,最流行的框架组合就是所谓的“SSM”,即SpringMVC+Spring+Mybatis

SSM虽好,但是通过搭建一个SSM项目还是比较繁琐的,需要大量的xml配置文件。
springboot整合了springmvc ,spring,mybatis 等核心功能。也就是说本质上实现功能的还是原有的spring ,springmvc的包,但是springboot单独包装了一层,这样用户就不必直接对springmvc, spring等,在xml中配置

3.2.2 Springboot 的优势

 不再需要那些千篇一律,繁琐的xml文件。
 内嵌Tomcat,不再需要外部的Tomcat
 更方便的和各个第三方工具(mysql,redis,elasticsearch,dubbo,kafka等等整合),而只要维护一个配置文件即可。

创建springboot项目

选择spring web 包括web应用的常用注解,以及web容器(默认tomcat,如果不勾选,项目没有web服务能力)

创建好后的,springboot的工程比maven的工程多了两个文件。其中:
DemoCustomerApplication 是整个程序的启动类。
application.properties 是整个工程的配置文件。

如果idea报红线 ,但是又觉没问题(以compile编译成功为准)

请求
请求 method 请求方式
get 读 post 写 ( put 写(幂等性写入) delete (删除) 不常用)
状态码(常见)
1xx 访问中未完成
2xx 已完成 200
3xx 跳转
4xx 客户端错误
400 bad request 参数不合格 ( 个数,类型)
403 禁止访问
405
404 not found 未找到资源
5xx 服务器错误
500 后台程序抛异常了 去看控制台 报错
6xx 及以上 自定义

web分层

分层 名称 职责 涉及的标签
controller 控制层 1 接收请求和参数。
2 调用服务层。
3 返回响应和结果。
⑥RestController。
⑦RequestMapping。
⑧RequestParam。
⑨RequestBody。
service 服务层(业务层) 1 接收控制层调用。
2 处理业务。
3 返回结果。
⑩Service。
⑪Autowired。
mapper 数据层 1 接收服务层调用。
2 数据库的操作(SQL)。
3 返回结果。
⑫Select。
⑬Insert。
⑭Delete。
⑮Update。
⑯Param。

注解说明

注释 位置 说明
@RestController 标识入口类。
@RequestMapping 方法 标识入口方法。
@GetMapping 方法 标识入口方法 GET 请求专用。
@PostMapping 方法 标识入口方法 POST 请求专用。
@RequestParam 参数 接收路径上的键值对参数。例如:http://xxxxx/xx?name=xxx&age=xxx
@PathVariable 参数 接收路径上的值。例如:http://xxxxx/customer/123
@RequestBody 参数 接收请求体(payload) 中的参数。

例如:http://xxxxx/xx?name=xxx&age=xxx参数多,可以用实体类接收。

3.4.3 实体类(bean 层)

更多 Java -大数据 -前端 -python 人工智能资料下载,可百度访问:尚硅谷官网。


尚硅谷

尚硅谷大数据项目之数据治理考评平台。


实体类的注解由 lombok_依赖提供。

注解 位置 说明
@NoArgsConstructor 增加无参构造函数。
@AllArgsConstructor 增加全参构造函数。
@Data 增加 getter setter 方法。

3.4.4 服务层 (Service 层)

3.4.4.1 职责

  1. 接收控制层调用。
  2. 处理业务。
  3. 返回结果。

3.4.4.2 注解说明

注解 位置 说明
@Service 声明该类为 Service 层 Spring 容器组件。
@Component 声明该类为 Spring 容器组件,功能上与 @Service 没有区别。
@Autowired 自动将 Spring 容器中的组件,装配到引用上。

一个服务可能被多个控制层调用,因此服务层需要通用性,
servers层先建接口:
因为1 同一个接口可以由多个实现类 通过 @Qualifier(“customer2”)
来选择适合的实现类
早期也可以通过xml来选择
2 用接口,成员可以完全不关心具体的实现类是什么
在分布式系统场景,程序员完全不关心远端的实现类在哪 如何部署 ,减轻程序员开发负担 ,部署环境尽量不影响业务逻辑

在控制层调用服务层,不需要new 一个对象,而是通过 Spring 容器获取到服务层的对象(随着容器的启动,Spring 容器会自动创建对象),然后调用其方法。用@Autowired 注解注入服务层对象。

1 容器(餐馆) – 组件(员工)
员工产生不会因为业务的调用 或者 其他员工的诞生而产生
所有组件的创建(new) 由容器的启动时统一创建
2 每个组件都是在容器中都是唯一的 ,单例模式(默认)

3 一般情况下 不要在单例组件上设置成员变量,因为成员变量是多线程共享的(多控制层调用同一个服务层),如果要设置比如 计数器 集合 ,要注意线程安全。例如: int count = 0 ;count++;变为AtomicInteger count = new AtomicInteger(0); count.addAndGet(1);

mybatis :
1 帮助程序员 连接数据 ,connection statement 一律省略

2 封装参数 select * from xxx where xxx = ?

3 封装结果
Customer UserInfo OrderInfo

使程序员 专注于完成sql

#{ } 一般就是用作参数传递 ,只传值 不传语句(类似jdbc中?)
${ } 一般用于动态拼接sql ,可以传语句

对单表做基础的查删改查 都不用再写sql了
mbp 提供了大量的crud 操作,包括mapper 层和 service层
无法实现join操作 ,union ,子查询 ,with …

mapper 建接口 mybatis帮你实现
数据源配置在application.properties中
和控制层调用服务层一样不用new 在service层用@Autowired 注解注入数据层对象。也可用BaseMapper,直接baseMapper.方法名(),(mybatis父类帮你创建了对象)

理论上控制层可以直接调mapper接口,但为了代码的可读性,还是建议用service层。

mybatis-plus:帮你写简单sql
在mapper接口上继承BaseMapper 即可T :实体类
在service接口上继承IService service实现类可以继承Serviceimpl<xxBaseMapper,T> 即可T :实体类 (可以) (可以避免service层写方法,在controller直接调用)
mybatis-plus 要求
每个java对象的属性和数据库字段必须一一对应
如果 某个Java属性不存在于数据库必须特殊声明

只改方法里的内容可以不用重启但要ctrl+f9刷新
如果该了注解或增加方法,需要重启项目。

java程序使用驼峰命名法,数据库字段使用下划线命名法。mybatis会自动将驼峰命名法转为下划线命名法。

json转换工具
Jackson spring 默认
Gson google

fastjson Alibaba
JSON.toJSONString(object) 对象转json字符串
JSON.parseObject(jsonString, Class clazz) json字符串转对象

Mybatis-plus的代码生成工具

增加一个代码生成的工具类
https://github.com/baomidou/generator

3.4.8 动态数据源
在实际开发中经常有面临一个Springboot应用要对接多个数据源的情况,但是如果通过配置完成多数据源与一个Springboot应用的连接实际上是非常繁琐的工作。
这里介绍一个动态数据源的工具dynamic-datasource。
这个工具只需要一个注解并配合简单的配置就可以实现一个Springboot对接多数据源。

在service层和 mapper的类上增加默认数据源(@Data(“dataSource1”))

在特定的方法上增加特定数据源
在 application.properties 中配置数据源信息

怎么看sql语句?
在aplication.properties中配置logging.level.com. … .mapper=debug(debug模式下可以看到sql语句)

连接池
数据连接池的主要目的是当应用反复访问数据库时,不会每次都重复创建连接。而是复用已有的连接。

连接池 作用就是避免 用户因为操作数据库 反复建立连接
连接池可以提前建立好连接 让用户从已有的连接池中借取
使用完毕后 归还连接池 而连接不会被销毁
n多个连接在池中循环使用 节省大量开销

在aplication.properties中配置连接池信息
再让使用连接池

lombok

apache lang3 google guava
小工具包
字符串切割 日期转换 等等 。。

sql 注入:
列:delete from xxxx where id=‘123’
页面传入 ‘ or 1=1
则会执行 delete from xxxx where id=‘‘ or 1=1
为避免SQL注入问题增加工具类
把服务拼接好的sql传入,因为${}有sql注入风险,需要在拼接sql时处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class SqlUtil {

public static String filterUnsafeSql(String input) {
if (input == null) {
return null;
}

// 替换 MySQL 中可能导致 SQL 注入的特殊字符
return input.replace("\\", "\\\\")
.replace("'", "\\'")
.replace("\"", "\\\"")
.replace("\b", "\\b")
.replace("\n", "\\n")
.replace("\r", "\\r")
.replace("\t", "\\t")
.replace("\u001A", "\\Z")
.replace("%", "\\%")
.replace("_", "\\_");
}
}

每增加一个指标

程序不需要改动任何一个已有类的代码
只需要增加一个新的类即可
低耦合 高内聚
开闭原则 ,对新增开发,对修改封闭
设计模式 模板模式
详情点我

@Component标识该类会被创建为容器组件,同时给组件赋予了名字“TEC_OWNER” ,这个标识名称用于从容器中获得对应的指标考评器。
增加一个工具类用于从 Spring容器中获得组件

在要用的地方引入工具类,调用方法

1
2
3
//从容器中获得对应名称的组件
Assessor assessor = SpringBeanProvider.getBean(governanceMetric.getMetricCode(), Assessor.class);
//根据名称获得spring容器中的组件

在子类中增加注解

1
@Component("TEC_OWNER")

添加工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Component
public class SpringBeanProvider implements ApplicationContextAware {
//继承上下文工具组件,用于获得上下文容器

private static ApplicationContext context;

private SpringBeanProvider(){}

//获取上下文对象,用于从容器中提取组件对象
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}

//从名称获取容器中的组件
public static <T> T getBean(String name,Class<T> aClass){
return context.getBean(name,aClass);
}
}

正则表达式
作用: 判断一个字符串符不符合 某种格式

开头 :一个字符串 含数字 英文大小_ 至少有1个字符 表开头:^[a-zA-Z0-9_] ^\w+
紧接着 @
紧接着:一个字符串 含数字 英文大小_ 1到 16个 \w{1,16}
接着 : . 注意 . 有特殊含义 标识任意一个字符
结尾: 要求 com或者cn org (练习)

^\w+@\w{1,16}.$(com|cn|org)

工具类的特点
1 不耦合业务逻辑

2 无状态 (连接,属性)

字符串.indexOf() 方法:
返回指定字符串在当前字符串中第一次出现的索引位置,如果当前字符串中不包含指定字符串,则返回 -1。

sql解析器

如何分析sql
1 把sql 变为结构体
语法树 解析语法树工具 最好 sql 是使用数据库 匹配
遍历器 用遍历器去访问语法数据

     自定义节点处理器 (业务逻辑)  把节点处理器放到遍历器中·

2 基于sql结构体 进行遍历检查
左右中
添加工具类

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

/**
*
* @param dispatcher 自定义节点处理器
* @param sql 待分析的sql
*/
public static void sqlParse(Dispatcher dispatcher, String sql ) {
try {

// 解析 Hive SQL
ParseDriver parseDriver = new ParseDriver(); //创建解析引擎
//执行解析 得到根节点
ASTNode ast = parseDriver.parse(sql);
// 找到查询的根节点下的TOK_QUERY节点,视为有效根节点
while (ast.getToken() == null || ast.getToken().getType() != HiveParser.TOK_QUERY) {
ast = (ASTNode) ast.getChild(0);
}

// 把节点处理器注入一个图形遍历器 使用自定义处理器遍历抽象语法树
GraphWalker ogw = new DefaultGraphWalker(dispatcher);
// 用遍历器遍历整个语法树
ogw.startWalking(Collections.singletonList(ast), null);

} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

异步编排

列如:求integer[] nums={1,2,3,4,5}的平方和

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//线程池
static ThreadPoolExecutor threadPoolExecutor= new ThreadPoolExecutor(10,20,60, TimeUnit.SECONDS,new LinkedBlockingDeque<>());

public static void main(String[] args) {
Integer[] nums= {1,2,3,4,5,6};
//取6个数的平方 然后加总 //假设每次取平方是复杂运算 每次需要计算5秒
long startTs = System.currentTimeMillis();
//创建CompletableFuture列表
List<CompletableFuture<Integer>> completableFutureList=new ArrayList<>();
//for循环不会等待所有任务完成 而是立即返回一个CompletableFuture对象
for (Integer num : nums) {
CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
//计算逻辑 并且有返回值 此处逻辑 开始 /////// //全部为异步执行,不会阻塞其他程序 包括外层循环
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return num * num;
/// ////////////////// 异步程序结束
}, threadPoolExecutor);
//添加到CompletableFuture列表
completableFutureList.add(completableFuture);

}
//等待所有任务完成 并获取求和的结果
List<Integer> integerList = completableFutureList.stream().map(future -> future.join()).collect(Collectors.toList());

Integer total=0;
for (Integer num : integerList) {
total+=num;
}
System.out.println(total);
System.out.println("System.currentTimeMillis()-startTs = " + (System.currentTimeMillis() - startTs));
//输出结果比30秒快 因为有并行计算
}

调度
11.5.1 springtask介绍
springtask是springboot框架中自带的时间调度程序。
优点:简单易用配置少。
缺点:不能做分布式调度

11.5.1.1 如何启用
在springboot启动程序上增加注解 @EnableScheduling

1
2
3
4
5
6
7
8
9
@SpringBootApplication
// 启动调度
@EnableScheduling
public class Application {

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

建立一个任务类,类上面增加@Component,在方法上增加表达式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.Date;

@Component
public class DemoTask {

@Scheduled(cron = "0/10 * * * * *")
public void text1(){
System.out.println("text1 测试"+DateFormatUtils.format(new Date(),"mm:ss"));
}

@Scheduled(fixedDelay = 5000)
public void text2(){
System.out.println("text2 测试"+ DateFormatUtils.format(new Date(),"mm:ss"));
}
@Scheduled(fixedRate = 5000)
public void text3(){
System.out.println("text3 测试"+DateFormatUtils.format(new Date(),"mm:ss"));
}
@Scheduled(initialDelay =3000, fixedRate = 5000)
public void text4(){
System.out.println("text4 测试"+DateFormatUtils.format(new Date(),"mm:ss"));
}
}

11.5.1.2 如何配置
@Scheduled可用的参数
 cron 表达式 标识 “秒 分 时 天 月 星期几”。
 fixedDelay标识 每次触发的固定间隔毫秒数,注意间隔为是前一次的结束时间到后一次的开始时间点的间隔。
 fixedRate 标识 每次触发的固定间隔毫秒数,注意间隔为是前一次的开始时间到后一次的开始时间点的间隔。 如果后一次开始时前一次的任务还没做完,则后一次的处理会被阻塞,直到前一任务完成。
 initialDelay 标识每次启动时初始的延迟, 可以配合fixedDelay 或者fixedRate使用

取配置文件中的自定义参数

@Value(“${assess.schemas}”)
String schemas=null;

在spring中dbug时要进入一个方法,最好不要用f7,在spring中 进入访问体验不好 因为方法可能被框架拦截,进入方法前 提前 用ctrl+alt+b 进入方法的实现类 打断点
再用F9 继续执行到该位置

报错优先看最后一个Caused by

[up主专用,视频内嵌代码贴在这]