xxl-job源码改造集成:适配opengauss数据、适配单点登录等

news2024/9/24 19:20:24

目录

一、摘要

二、集成方案

三、集成步骤

3.1 springboot集成xxl-job

3.2 适配高斯数据库(postgresql)

3.3 页面集成

3.4 登录集成

3.5 接口集成

四、部署


一、摘要

        公司现在打算重构产品,将原来的quartz替换成xxl-job,主要因为quartz不能动态发布任务,而xxl-job开箱即用,还支持一系列新特性,有 动态编写任务、调度中心和执行器高可用(可集群部署)、任务路由策略多样、 弹性扩容、失败重试 等。

二、集成方案

        xxl-job架构分为管理端(调度中心)和客户端(各应用执行器),由调度中心调用各执行器执行任务,而且它有自己的用户和角色以及页面,目前只有mysql初始化脚本。因此公司产品集成xxl-job,主要有以下几点需要集成:

        1、数据库集成:公司的产品是需要适配mysql和opengauss,因此xxl-job也需要适配opengauss,改造方案为:初始化脚本需要有opengauss版本的SQL、接口与后台任务运行的不兼容的SQL用改成兼容通用语法或修改逻辑用mybatis plus兼容,实在不行的则配置DatabaseIdProvider并用databaseId区分两种数据库的SQL,数据源配置统一改成公司的数据源配置。

        2、页面集成:由于xxl-job页面风格不一致、且页面不支持配置任务执行时间段,这里任务管理页面还是采用原公司任务管理页面,然后再开发个任务源码编辑查看页。任务管理页面的菜单和按钮权限还是和以前权限管理设置一样,不同的角色和用户设置不同的任务管理菜单和按钮。

        3、登录集成:由于公司有自己的单点登录,因此需要将xxl-job的鉴权适配,改造方案为:登录拦截器改造,接口request里若没有符合单点登录的token则跳转公司登录页,若有token则给用户赋管理员权限。

        4、接口集成:调用quartz的接口全部改成调用xxl-job,任务运行的注解也改成xxl-job的注解。

三、集成步骤

3.1 springboot集成xxl-job

         这里先确定xxl-job的版本,看xxl-job在gitee和github的代码,人们对2.3.1的版本提的问题较少,且2.3.1也能满足需求,新特性都支持,这里选择2.3.1版本,然后下载下来。

   

        下载后,得到源码如下:

 

         可以看到,这里有三个模块:xxl-job-admin(调度中心)、xxl-job-core(执行器需添加的依赖)、xxl-job-executor-samples(执行器示例)。

        初始化数据库的SQL也有,具体如下:

        找个mysql数据库运行下初始化脚本,然后改改xxl-job-admin里的配置(数据源、端口)再启动,访问管理页面,默认情况为 ip:8080/xxl-job-admin,首次登录会跳转登录页,用amdin/123456登录后可以看到类似如下首页:

         执行器可以参考 xxl-job-executor-sample-springboot的示例来配置。主要是加入xxl-job-core依赖,声明好 ip、port、appname以及admin.addresses。注意的是,执行器的appname一定要在admin的执行器管理里进行添加,执行器才能连上admin(这个类似于先在调度中心申请一个凭证appname,后续执行器用凭证appname连上admin)。具体如下:

         测试可行后,原定时任务在系统管理模块,因此,系统管理模块需加入xxl-job-core依赖并进行配置作为执行器、项目里需新建定时任务管理模块(存放xxl-job-admin代码)作为调度中心。

        具体目录结构如下:

3.2 适配高斯数据库(postgresql)

        由于高斯数据库完全支持postgresql语法,所以根据xxl-job的mysql表结构编写pg的SQL,具体如下:

CREATE TABLE xxl_job_info (
  id serial constraint xxl_job_info_pkey primary key,
  job_group integer NOT NULL,
  job_desc varchar(255) NOT NULL,
  add_time timestamp DEFAULT NULL,
  update_time timestamp DEFAULT NULL,
  author varchar(64) DEFAULT NULL ,
  alarm_email varchar(255) DEFAULT NULL ,
  schedule_type varchar(50) NOT NULL DEFAULT 'NONE' ,
  schedule_conf varchar(128) DEFAULT NULL,
  misfire_strategy varchar(50) NOT NULL DEFAULT 'DO_NOTHING' ,
  executor_route_strategy varchar(50) DEFAULT NULL ,
  executor_handler varchar(255) DEFAULT NULL ,
  executor_param varchar(512) DEFAULT NULL ,
  executor_block_strategy varchar(50) DEFAULT NULL ,
  executor_timeout integer NOT NULL DEFAULT '0',
  executor_fail_retry_count integer NOT NULL DEFAULT '0' ,
  glue_type varchar(50) NOT NULL ,
  glue_source text ,
  glue_remark varchar(128) DEFAULT NULL ,
  glue_updatetime timestamp DEFAULT NULL ,
  child_jobid varchar(255) DEFAULT NULL ,
  trigger_status smallint NOT NULL DEFAULT '0' ,
  trigger_last_time bigint NOT NULL DEFAULT '0' ,
  trigger_next_time bigint NOT NULL DEFAULT '0'
);

comment on table xxl_job_info is '任务信息表';
comment on column xxl_job_info.id  is '主键';
comment on column xxl_job_info.job_group  is '执行器主键ID';
comment on column xxl_job_info.job_desc  is '任务描述';
comment on column xxl_job_info.add_time  is '任务创建时间';
comment on column xxl_job_info.update_time  is '任务更新时间';
comment on column xxl_job_info.author  is '作者';
comment on column xxl_job_info.alarm_email  is '报警邮件';
comment on column xxl_job_info.schedule_type  is '调度类型';
comment on column xxl_job_info.schedule_conf  is '调度配置,值含义取决于调度类型';
comment on column xxl_job_info.misfire_strategy  is '调度过期策略';
comment on column xxl_job_info.executor_route_strategy  is '执行器路由策略';
comment on column xxl_job_info.executor_handler  is '执行器任务handler';
comment on column xxl_job_info.executor_param is '执行器任务参数';
comment on column xxl_job_info.executor_block_strategy  is '阻塞处理策略';
comment on column xxl_job_info.executor_timeout  is '任务执行超时时间,单位秒';
comment on column xxl_job_info.executor_fail_retry_count  is '失败重试次数';
comment on column xxl_job_info.glue_type  is 'GLUE类型';
comment on column xxl_job_info.glue_source  is 'GLUE源代码';
comment on column xxl_job_info.glue_remark  is 'GLUE备注';
comment on column xxl_job_info.glue_updatetime  is 'GLUE更新时间';
comment on column xxl_job_info.child_jobid  is '子任务ID,多个逗号分隔';
comment on column xxl_job_info.trigger_status  is '调度状态:0-停止,1-运行';
comment on column xxl_job_info.trigger_last_time  is '上次调度时间';
comment on column xxl_job_info.trigger_next_time  is '下次调度时间';


CREATE TABLE xxl_job_log (
  id serial constraint xxl_job_log_pkey primary key,
  job_group integer NOT NULL,
  job_id integer NOT NULL,
  executor_address varchar(255) DEFAULT NULL,
  executor_handler varchar(255) DEFAULT NULL,
  executor_param varchar(512) DEFAULT NULL,
  executor_sharding_param varchar(20) DEFAULT NULL ,
  executor_fail_retry_count integer NOT NULL DEFAULT '0',
  trigger_time timestamp DEFAULT NULL,
  trigger_code integer NOT NULL,
  trigger_msg text,
  handle_time timestamp DEFAULT NULL,
  handle_code integer NOT NULL,
  handle_msg text ,
  alarm_status smallint NOT NULL DEFAULT '0'
) ;

CREATE INDEX I_trigger_time ON xxl_job_log (trigger_time);
CREATE INDEX I_handle_code ON xxl_job_log (handle_code);
comment on table xxl_job_log is '任务日志表';
comment on column xxl_job_log.id  is '主键';
comment on column xxl_job_log.job_group  is '执行器主键ID';
comment on column xxl_job_log.job_id  is '任务,主键ID';
comment on column xxl_job_log.executor_address  is '执行器地址,本次执行的地址';
comment on column xxl_job_log.executor_handler  is '执行器任务handler';
comment on column xxl_job_log.executor_param  is '执行器任务参数';
comment on column xxl_job_log.executor_sharding_param  is '执行器任务分片参数,格式如 1/2';
comment on column xxl_job_log.executor_fail_retry_count  is '失败重试次数';
comment on column xxl_job_log.trigger_time  is '调度-时间';
comment on column xxl_job_log.trigger_code  is '调度-结果';
comment on column xxl_job_log.trigger_msg  is '调度-日志';
comment on column xxl_job_log.handle_time  is '执行-时间';
comment on column xxl_job_log.handle_code  is '执行-状态';
comment on column xxl_job_log.handle_msg  is '执行-日志';
comment on column xxl_job_log.alarm_status  is '告警状态:0-默认、1-无需告警、2-告警成功、3-告警失败';


create or replace function upd_timestamp() returns trigger as
$$
begin
    new.update_time = current_timestamp;
    return new;
end
$$
    language plpgsql;


CREATE TABLE xxl_job_log_report (
  id serial constraint xxl_job_log_report_pkey primary key,
  trigger_day timestamp DEFAULT NULL,
  running_count integer NOT NULL DEFAULT '0',
  suc_count integer NOT NULL DEFAULT '0',
  fail_count integer NOT NULL DEFAULT '0',
  update_time timestamp DEFAULT NULL
);

CREATE UNIQUE INDEX i_trigger_day ON xxl_job_log_report (trigger_day);
comment on column  xxl_job_log_report.id  is '主键';
comment on column  xxl_job_log_report.trigger_day  is '调度-时间';
comment on column  xxl_job_log_report.running_count  is '运行中-日志数量';
comment on column  xxl_job_log_report.suc_count  is '执行成功-日志数量';
comment on column  xxl_job_log_report.fail_count  is '执行失败-日志数量';
comment on column  xxl_job_log_report.update_time  is '更新时间';


CREATE TABLE xxl_job_logglue (
  id serial constraint xxl_job_logglue_pkey primary key,
  job_id integer NOT NULL,
  glue_type varchar(50) DEFAULT NULL,
  glue_source text,
  glue_remark varchar(128) NOT NULL,
  add_time timestamp DEFAULT NULL,
  update_time timestamp DEFAULT NULL
);

create trigger t_xxl_job_logglue_update_time before update on xxl_job_logglue for each row execute procedure upd_timestamp();
comment on table xxl_job_logglue is '任务GLUE日志表';
comment on column xxl_job_logglue.id  is '主键';
comment on column xxl_job_logglue.job_id  is '任务,主键ID';
comment on column xxl_job_logglue.glue_type  is 'GLUE类型';
comment on column xxl_job_logglue.glue_source  is 'GLUE源代码';
comment on column xxl_job_logglue.glue_remark  is 'GLUE备注';
comment on column xxl_job_logglue.add_time  is '创建时间';
comment on column xxl_job_logglue.update_time  is '修改时间';

CREATE TABLE xxl_job_registry (
  id serial constraint xxl_job_registry_pkey primary key,
  registry_group varchar(50) NOT NULL,
  registry_key varchar(255) NOT NULL,
  registry_value varchar(255) NOT NULL,
  update_time timestamp DEFAULT NULL
);
CREATE INDEX i_g_k_v ON xxl_job_registry (registry_group,registry_key,registry_value);
comment on table xxl_job_registry is '任务注册表';
comment on column xxl_job_registry.id  is '主键';
comment on column xxl_job_registry.registry_group  is '注册分组';
comment on column xxl_job_registry.registry_key  is '注册键';
comment on column xxl_job_registry.registry_value  is '注册值';
comment on column xxl_job_registry.update_time  is '更新时间';


CREATE TABLE xxl_job_group (
  id serial constraint xxl_job_group_pkey primary key,
  app_name varchar(64) NOT NULL,
  title varchar(12) NOT NULL,
  address_type smallint NOT NULL DEFAULT '0',
  address_list text ,
  update_time timestamp DEFAULT NULL
);

comment on table xxl_job_group is '任务分组表';
comment on column xxl_job_group.id  is '主键';
comment on column xxl_job_group.app_name  is '执行器AppName';
comment on column xxl_job_group.title  is '执行器名称';
comment on column xxl_job_group.address_type  is '执行器地址类型:0=自动注册、1=手动录入';
comment on column xxl_job_group.address_list  is '执行器地址列表,多地址逗号分隔';


CREATE TABLE xxl_job_user (
  id serial constraint xxl_job_user_pkey primary key,
  username varchar(50) NOT NULL,
  password varchar(50) NOT NULL,
  role smallint NOT NULL,
  permission varchar(255) DEFAULT NULL
) ;


CREATE UNIQUE INDEX i_username ON xxl_job_user (username);
comment on table xxl_job_user is '任务用户表';
comment on column xxl_job_user.id  is '主键';
comment on column xxl_job_user.username  is '账号';
comment on column xxl_job_user.password  is '密码';
comment on column xxl_job_user.role  is '角色:0-普通用户、1-管理员';
comment on column xxl_job_user.permission  is '权限:执行器ID列表,多个逗号分割';


CREATE TABLE xxl_job_lock (
  lock_name varchar(50) NOT NULL,
  PRIMARY KEY (lock_name)
);

comment on table xxl_job_lock is '任务锁表';
comment on column xxl_job_lock.lock_name  is '锁名称';

INSERT INTO xxl_job_group( app_name, title, address_type, address_list, update_time) VALUES ('xxl-job-executor-sample', '示例执行器', 0, NULL, '2018-11-03 22:21:31' );
INSERT INTO xxl_job_info( job_group, job_desc, add_time, update_time, author, alarm_email, schedule_type, schedule_conf, misfire_strategy, executor_route_strategy, executor_handler, executor_param, executor_block_strategy, executor_timeout, executor_fail_retry_count, glue_type, glue_source, glue_remark, glue_updatetime, child_jobid) VALUES ( 1, '测试任务1', '2018-11-03 22:21:31', '2018-11-03 22:21:31', 'XXL', '', 'CRON', '0 0 0 * * ? *', 'DO_NOTHING', 'FIRST', 'demoJobHandler', '', 'SERIAL_EXECUTION', 0, 0, 'BEAN', '', 'GLUE代码初始化', '2018-11-03 22:21:31', '');
INSERT INTO xxl_job_user( username, password, role, permission) VALUES ( 'admin', 'e10adc3949ba59abbe56e057f20f883e', 1, NULL);
INSERT INTO xxl_job_lock ( lock_name) VALUES ( 'schedule_lock');

        接着xml文件里将“`”去除,具体如下:

        调整findDead逻辑,原SQL(<![CDATA[ < ]]> DATE_ADD(#{nowTime},INTERVAL -#{timeout} SECOND))不兼容pg语法, 如下:

        这句SQL是找出更新时间小于(当前时间-配置的超时时间)的注册组,查了下网上写法,都不怎么好,这里改用集成mybatis plus,用mybatis plus来进行查询。具体如下:

        另外,使用了mybatis plus,有些表会发生主键插入异常,具体解决办法如下:

        调整不等于判断,具体如下:

         将驼峰改成小写适配高斯数据库

         基本就以上这些了,连接pg数据库也能正常运行admin并新增执行器和任务运行,并能看到日志以及统计。

3.3 页面集成

        页面集成意味着客户无法看到admin管理页,只能看到原来的任务页,原页面如下:

        目前页面保持不变,页面的对应的菜单和按钮权限都不变,接口的url以及参数和返回值都不变,xxl-job-admin的管理页对用户不可见,我这里修改路径和端口,并不暴露给前端和nginx。由于管理页不可见,需要把新增执行器appname的sql写在初始化SQL里。

3.4 登录集成

        这里调整拦截器PermissionInterceptor和toLogin处理即可。具体如下:

         这里PermissionInterceptor拦截器去除needAdminUser判断,直接从request里获取token,获取不到或根据token查不到登录用户信息,则跳转toLogin,若能获取到用户登录信息,则给用户赋值xxl-job的管理员权限并保存到request的属性中即可。

         这里toLogin处理直接重定向公司的单点登录地址即可。

3.5 接口集成

        这里系统管理模块里原来任务controller保持不变,服务层原来调用quartz的逻辑全部换成xxl-job。具体如下:

         系统管理模块(执行器)保存时调用feign接口,进而调用xxl-job-admin的新增方法。这里通过任务参数关联系统管理的任务,后续执行器执行任务时,可以通过任务参数找到添加的任务配置,进而进行相应处理。任务注解就简单了,换用@XxlJob注解即可。剩下的任务业务逻辑各自按业务进行调整。

四、部署

        这里考虑高可用,所以系统管理模块(执行器)和任务管理模块(调度中心xxl-job-admin)都是集群部署。这里部署需要注意,所有机器的时间必须保持一致。调度中心连接同一个数据库多实例启动即可,执行器配在admin.address配置各调度中心的地址后多实例启动即可。

      


 

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

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

相关文章

多通道分离与合并

1、分离 2、合并 Mat img imread("F:/testMap/plan.png");Mat imgs[3];split(img,imgs);//分离Mat img0,img1,img2;img0 imgs[0];img1 imgs[1]; img2 imgs[2];Mat img_H;merge(imgs,3,img_H);//合并vector<Mat> imgsV; imgsV.push_back(img0);imgsV.push_b…

5.8.3 TCP连接管理(一)TCP连接建立

5.8.3 TCP连接管理&#xff08;一&#xff09;TCP连接建立 我们知道TCP是面向连接的传输协议&#xff0c;在传输连接的建立和释放是每一次面向连接通信必不可少的过程&#xff0c;因此传输连接的管理使得传输连接的建立和释放的过程都能够正常的进行。 一、使用Wireshark查看…

UE4/5用GeneratedDynamicMeshActor网格细分静态网格体【用的是ue5建模模式的box,其他的没有作用】

目录 制作 逻辑&#xff1a; 效果&#xff1a; ​编辑 代码&#xff1a; 制作 前面和之前的流程一样&#xff0c;打开插件和继承GeneratedDynamicMeshActor创建一个蓝图&#xff1a; 逻辑&#xff1a; 两个函数对应了两种细分方法 上面的细分模式是&#xff1a;Loop细…

JupyterNotebook基本操作

目录 Jupyter notebook文件操作 创建文件 修改文件名 复制文件 移动文件 删除文件 上传文件 下载文件 Jupyter notebook单元格操作 内容类型 编辑模式 快捷键 对照表 命令模式 编辑模式 查看快捷键 进入Jupyter Notebook主界面“File”中 VSCode配置Jupyter…

Bootstrap 表单

文章目录 Bootstrap 表单表单布局垂直或基本表单内联表单水平表单支持的表单控件输入框&#xff08;Input&#xff09;文本框&#xff08;Textarea&#xff09;复选框&#xff08;Checkbox&#xff09;和单选框&#xff08;Radio&#xff09;选择框&#xff08;Select&#xff…

【Go】Go 语言教程--介绍(一)

文章目录 Go 语言特色Go 语言用途第一个 Go 程序Go 语言环境安装UNIX/Linux/Mac OS X, 和 FreeBSD 安装Windows 系统下安装安装测试 Go 是一个开源的编程语言&#xff0c;它能让构造简单、可靠且高效的软件变得容易。 Go是从2007年末由Robert Griesemer, Rob Pike, Ken Thompso…

文生图技术stable diffusion入门实战

文章目录 0. 环境搭建0.1 Windows0.1.1 git环境安装0.1.2 python 环境搭建0.1.2.1 配置pip国内镜像源 0.1.3 stable diffusion环境搭建0.1.3.1 远程访问Stable diffusion 1. 基础知识1.1 Stable Diffusion Webui及基础参数1.2 参数说明 0. 环境搭建 0.1 Windows 0.1.1 git环境…

电子时钟制作(瑞萨RA)(3)----使用J-Link烧写程序到瑞萨芯片

概述 这一节主要讲解如何使用J-Link对瑞萨RA芯片进行烧录。 硬件准备 首先需要准备一个开发板&#xff0c;这里我准备的是芯片型号R7FA2E1A72DFL的开发板&#xff1a; 视频教程 https://www.bilibili.com/video/BV1kX4y1v7tL/ 电子时钟制作(瑞萨RA)----(2)使用串口进行程序…

初学spring5(八)整合MyBatis

学习回顾&#xff1a;初学spring5&#xff08;七&#xff09;AOP就这么简单 一、步骤 1、导入相关jar包 junit <dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version> </dependency>m…

如何使用RobotFramework编写好的测试用例

目录 概述 命名 测试套件命名 测试用例命名 关键字命名 setup和teardown的命名 文档 测试套件文档 测试用例文档 用户关键字文档 测试套件结构 测试用例结构 工作流测试 数据驱动测试 用户关键字 变量 变量的命名 传参和返回值 避免使用Sleep关键字 我们AT…

算法设计与分析 课程期末复习简记(更新中)

网络流 下面是本章需要掌握的知识 • 流量⽹络的相关概念 • 最⼤流的概念 • 最⼩割集合的概念 • Dinic有效算法的步骤 • 会⼿推⼀个流量⽹络的最⼤流 下面对此依次进行复习 首先看流量网络的相关概念 上面是课程PPT中的定义&#xff0c;真是抽象 实际上&#xff0c;我们直接…

Maynor的博客专家成长之路——暨2023年中复盘

文章目录 博客专家成长之路——暨2023年中复盘前言念念不忘的博客专家每天只做三件事敲代码写博客健健身 我的感悟 不足之处未来&#xff1a;和CSDN共同成长最后 博客专家成长之路——暨2023年中复盘 前言 ​ 2023年不知不觉已经过去了半年有余&#xff0c;也是时候作年中复盘…

WEB界面测试

目录 前言&#xff1a; 摘要: WEB界面测试&#xff0c;最大的难度之一可能就是兼容性测试了 WEB界面测试&#xff0c;注重用户体验 WEB界面测试&#xff0c;注意用户的使用习惯 前言&#xff1a; Web界面测试是一种通过模拟用户与Web应用程序的交互来验证其功能和用户体验…

基于自然语言处理的多模态模型_综述

A Survey on Multimodal Large Language Models&#xff1b; 论文链接&#xff1a;https://arxiv.org/pdf/2306.13549.pdf 项目链接(实时更新最新论文&#xff0c;已获1.8K Stars)&#xff1a;https://github.com/BradyFU/Awesome-Multimodal-Large-Language-Models 研究背景 …

线程安全问题之原因及解决方案

线程安全问题 根本原因代码结构原子性解决方案&#xff1a;synchronized 内存可见性问题解决方案 volatile 指令重排序问题wait和notify判定一个代码是否线程安全&#xff0c;一定要具体问题具体分析!!! 根本原因 根本原因&#xff1a;多线程抢占式执行&#xff0c;随机调度。 …

ESP8266-NodeMCU搭建Arduino IDE开发环境

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、准备工作二、搭建步骤1.打开Arduino IDE 首选项2.打开Arduino IDE的“开发板管理器”3.在Arduino IDE的开发板菜单中找到“NodeMCU开发板”4.设置Arduino IDE的…

实验二:子程序设计实验

一、实验目的闻明找强的的掌握于程府的定又和调用方法掌握子程布的程库设计与调试方法 实验要求. 说明实现本实验需要掌握的知识及本实验害要的实验环境 二、实验要求了解萄单汇师培长程产没计与调武了解江编语子能店定义了解汇编语着子程序设计 实验内容 阐明实验具体内容及实…

3. Linux组件之内存池的实现

文章目录 一、为什么需要内存池二、内存池的工作流程三、内存池的实现3.1 数据结构3.2 接口设计3.2.1 创建内存池3.2.2 内存池销毁3.2.3 内存分配1. 分配小块内存2. 分配大块内存 3.2.4 内存池的释放3.2.5 内存池重置 3.3 完整代码 一、为什么需要内存池 应用程序使用内存&…

【我们一起60天准备考研算法面试(大全)-第一天 1/60(排序、进制)】【每天40分钟,我们一起用60天准备 考研408-数据结构(笔试)】

专注 效率 记忆 预习 笔记 复习 做题 欢迎观看我的博客&#xff0c;如有问题交流&#xff0c;欢迎评论区留言&#xff0c;一定尽快回复&#xff01;&#xff08;大家可以去看我的专栏&#xff0c;是所有文章的目录&#xff09;   文章字体风格&#xff1a; 红色文字表示&#…

与彭老师交流(北京大学 心理与认知科学学院)

交流&#xff1a;主要是了解人家在做什么对什么感兴趣&#xff0c;和让人家知道你在做什么对什么感兴趣&#xff0c;然后你觉得未来可以做什么有价值的事情。 1.老师做的方向里面有包含利用人工智能这一块的知识&#xff0c;我觉得我是可以做的&#xff0c;机理这一块的东西我不…