【React系列】Redux(二)中间件
本文来自#React系列教程:https://mp.weixin.qq.com/mp/appmsgalbum?__biz=Mzg5MDAzNzkwNA==&action=getalbum&album_id=1566025152667107329)
一. 中间件的使用
1.1. 组件中异步请求
在之前简单的案例中,redux中保存的counter
是一个本地定义的数据,我们可以直接通过同步的操作来dispatch action
,state
就会被立即更新。
但是真实开发中,redux中保存的很多数据可能来自服务器,我们需要进行异步的请求,再将数据保存到redux中。
在之前学习网络请求的时候我们讲过,网络请求可以在class
组件的componentDidMount
中发送,所以我们可以有这样的结构:
我现在完成如下案例操作:
- 在
Home
组件中请求banners
和recommends
的数据; - 在
Profile
组件中展示banners
和recommends
的数据;
redux代码进行如下修改:
在reducer.js
中添加state
初始化数据和reducer
函数中处理代码:
const initialState = {counter: 0,banners: [],recommends: []
}function reducer(state = initialState, action) {switch (action.type) {case ADD_NUMBER:return { ...state, counter: state.counter + action.num };case SUB_NUMBER:return { ...state, counter: state.counter - action.num };case CHANGE_BANNER:return { ...state, banners: action.banners };case CHANGE_RECOMMEND:return { ...state, recommends: action.recommends };default:return state;}
}
constants
中增加常量:
const CHANGE_BANNER = "CHANGE_BANNER";
const CHANGE_RECOMMEND = "CHANGE_RECOMMEND";
actionCreators.js
中添加actions
:
const changeBannersAction = (banners) => ({type: CHANGE_BANNER,banners
}) const changeRecommendsAction = (recommends) => ({type: CHANGE_RECOMMEND,recommends
})
组件中代码代码修改:
Home
组件:
import React, { PureComponent } from 'react';
import { connect } from "react-redux";import axios from 'axios';import {addAction,changeBannersAction,changeRecommendsAction
} from '../store/actionCreators';class Home extends PureComponent {componentDidMount() {axios.get("http://123.207.32.32:8000/home/multidata").then(res => {const data = res.data.data;this.props.changeBanners(data.banner.list);this.props.changeRecommends(data.recommend.list);})}...其他业务代码
}const mapStateToProps = state => {return {counter: state.counter}
}const mapDispatchToProps = dispatch => {return {addNumber: function(number) {dispatch(addAction(number));},changeBanners(banners) {dispatch(changeBannersAction(banners));},changeRecommends(recommends) {dispatch(changeRecommendsAction(recommends));}}
}export default connect(mapStateToProps, mapDispatchToProps)(Home);
Profile
组件:
import React, { PureComponent } from 'react';
import { connect } from "react-redux";import {subAction
} from '../store/actionCreators';class Profile extends PureComponent {render() {return (<div>Profile<div><h2>当前计数: {this.props.counter}</h2><button onClick={e => this.decrement()}>-1</button><button onClick={e => this.subCounter()}>-5</button></div><h1>Banners</h1><ul>{this.props.banners.map((item, index) => {return <li key={item.acm}>{item.title}</li>})}</ul><h1>Recommends</h1><ul>{this.props.recommends.map((item, index) => {return <li key={item.acm}>{item.title}</li>})}</ul></div>)}...其他逻辑代码
}const mapStateToProps = state => {return {counter: state.counter,banners: state.banners,recommends: state.recommends}
}const mapDispatchToProps = dispatch => {return {subNumber: function (number) {dispatch(subAction(number));}}
}export default connect(mapStateToProps, mapDispatchToProps)(Profile);
1.2. redux中异步请求
上面的代码有一个缺陷:
- 我们必须将网络请求的异步代码放到组件的生命周期中来完成;
- 事实上,网络请求到的数据也属于我们状态管理的一部分,更好的一种方式应该是将其也交给redux来管理;
但是在redux中如何可以进行异步的操作呢?
- 答案就是使用中间件(Middleware);
- 学习过Express或Koa框架的童鞋对中间件的概念一定不陌生;
- 在这类框架中,Middleware可以帮助我们在请求和响应之间嵌入一些操作的代码,比如
cookie
解析、日志记录、文件压缩等操作;
redux也引入了中间件(Middleware)的概念:
- 这个中间件的目的是在
dispatch
的action
和最终达到的reducer
之间,扩展一些自己的代码; - 比如日志记录、调用异步接口、添加代码调试功能等等;
我们现在要做的事情就是发送异步的网络请求,所以我们可以添加对应的中间件:
- 这里官网推荐的、包括演示的网络请求的中间件是使用
redux-thunk
;
redux-thunk
是如何做到让我们可以发送异步的请求呢?
- 我们知道,默认情况下的
dispatch(action)
,action
需要是一个JavaScript的对象; redux-thunk
可以让dispatch(action函数)
,action
可以是一个函数;- 该函数会被调用,并且会传给这个函数一个
dispatch
函数和getState
函数;dispatch
函数用于我们之后再次派发action
;getState
函数考虑到我们之后的一些操作需要依赖原来的状态,用于让我们可以获取之前的一些状态;
如何使用 redux-thunk 呢?
- 安装 redux-thunk
yarn add redux-thunk
- 在创建
store
时传入应用了middleware
的enhance
函数
- 通过
applyMiddleware
来结合多个Middleware
, 返回一个enhancer
; - 将
enhancer
作为第二个参数传入到createStore
中;
// 通过applyMiddleware来结合多个Middleware, 返回一个enhancer
const enhancer = applyMiddleware(thunkMiddleware);
// 将enhancer作为第二个参数传入到createStore中
const store = createStore(reducer, enhancer);
- 定义返回一个函数的
action
:
const getHomeMultidataAction = () => {return (dispatch) => {axios.get("http://123.207.32.32:8000/home/multidata").then(res => {const data = res.data.data;dispatch(changeBannersAction(data.banner.list));dispatch(changeRecommendsAction(data.recommend.list));})}
}
- 注意:这里不是返回一个对象了,而是一个函数;
- 该函数在
dispatch
之后会被执行;
- 修改
home.js
中的代码:
import React, { PureComponent } from 'react';
import { connect } from "react-redux";import {addAction,getHomeMultidataAction
} from '../store/actionCreators';class Home extends PureComponent {componentDidMount() {this.props.getHomeMultidata();}...其他逻辑代码
}...mapStatetoPropsconst mapDispatchToProps = dispatch => {return {addNumber: function(number) {dispatch(addAction(number));},getHomeMultidata() {dispatch(getHomeMultidataAction());}}
}export default connect(mapStateToProps, mapDispatchToProps)(Home);
1.3. redux-devtools
我们之前讲过,redux可以方便的让我们对状态进行跟踪和调试,那么如何做到呢?
- redux官网为我们提供了
redux-devtools
的工具; - 利用这个工具,我们可以知道每次状态是如何被修改的,修改前后的状态变化等等;
安装该工具需要两步:
- 第一步:在对应的浏览器中安装相关的插件(比如Chrome浏览器扩展商店中搜索Redux DevTools即可,其他方法可以参考GitHub);
- 第二步:在redux中集成devtools
import { createStore, applyMiddleware, compose } from 'redux';
import thunkMiddleware from 'redux-thunk';
import reducer from './reducer.js';const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;// 通过applyMiddleware来结合多个Middleware, 返回一个enhancer
const enhancer = composeEnhancers(applyMiddleware(thunkMiddleware));
// 将enhancer作为第二个参数传入到createStore中
const store = createStore(reducer, enhancer);export default store;
trace打开:
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({trace: true}) || compose;
1.4. redux-saga
1.4.1. ES6的generator
saga中间件使用了ES6的generator
语法,所以我们有必须简单讲解一下:
- 注意:我这里并没有列出
generator
的所有用法,事实上它的用法非常的灵活,大家可以自行去学习一下。
在JavaScript中编写一个普通的函数,进行调用会立即拿到这个函数的返回结果:
function foo() {return "Hello World";
}foo() // Hello World
如果我们将这个函数编写成一个生成器函数:
function *foo() {yield "Hello";yield "World";
}const iterator = foo();
console.log(iterator, typeof iterator); // 一个object类型的iterator对象
调用iterator
的next
函数,会销毁一次迭代器,并且返回一个yield
的结果:
// 调用一次next()是消耗一次迭代器
iterator.next(); // {value: "Hello", done: false}
iterator.next(); // {value: "World", done: false}
iterator.next(); // {value: undefined, done: true}
研究一下foo
生成器函数代码的执行顺序:
function *foo() {console.log("111111");yield "Hello";console.log("222222");yield "World";console.log("333333");
}// 调用一次next()是消耗一次迭代器
iterator.next(); // {value: "Hello", done: false}
// 打印111111
iterator.next(); // {value: "World", done: false}
// 打印222222
iterator.next(); // {value: undefined, done: true}
// 打印333333
generator
和promise
一起使用:
function *bar() {const result = yield new Promise((resolve, reject) => {setTimeout(() => {resolve("Hello Generator");return "Hello";}, 2000);});console.log(result);
}const bIterator = bar();
bIterator.next().value.then(res => {bIterator.next(res);
});
1.4.2. redux-saga的使用
- 装 redux-saga
yarn add redux-saga
- 集成 redux-saga 中间件
import { createStore, applyMiddleware, compose } from 'redux';
import thunkMiddleware from 'redux-thunk';
import createSagaMiddleware from 'redux-saga';
import reducer from './reducer.js';
import mySaga from './saga';// 通过createSagaMiddleware函数来创建saga中间件
const sagaMiddleware = createSagaMiddleware();const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({trace: true}) || compose;// 通过applyMiddleware来结合多个Middleware, 返回一个enhancer
const enhancer = composeEnhancers(applyMiddleware(thunkMiddleware, sagaMiddleware));
// 将enhancer作为第二个参数传入到createStore中
const store = createStore(reducer, enhancer);// 必须启动saga中间件,并且传入其要监听的generator
sagaMiddleware.run(mySaga);export default store;
saga.js
文件的编写:
import { takeEvery, put, all } from 'redux-saga/effects';
import axios from 'axios';import {FETCH_HOME_MULTIDATA
} from "./constants";
import {changeBannersAction,changeRecommendsAction,
} from './actionCreators';function* fetchHomeMultidata(action) {const res = yield axios.get("http://123.207.32.32:8000/home/multidata");console.log(res);const data = res.data.data;yield all([put(changeBannersAction(data.banner.list)),put(changeRecommendsAction(data.recommend.list))])
}function* mySaga() {yield takeEvery(FETCH_HOME_MULTIDATA, fetchHomeMultidata)
}export default mySaga;
takeEvery
:可以传入多个监听的actionType
,每一个都可以被执行(对应有一个takeLastest
,会取消前面的)put
:在saga中派发action
不再是通过dispatch
,而是通过put
;all
:可以在yield
的时候put
多个action
;
二. 中间件的原理
2.1. 打印日志需求
前面我们已经提过,中间件的目的是在redux中插入一些自己的操作:
- 比如我们现在有一个需求,在
dispatch
之前,打印一下本次的action
对象,dispatch
完成之后可以打印一下最新的store state
; - 也就是我们需要将对应的代码插入到redux的某部分,让之后所有的
dispatch
都可以包含这样的操作;
如果没有中间件,我们是否可以实现类似的代码呢?
当然可以,类似下面的方式即可:
console.log("dispatching:", addAction(5));
store.dispatch(addAction(5));
console.log("new state:", store.getState());console.log("dispatching:", addAction(10));
store.dispatch(subAction(10));
console.log("new state:", store.getState());
但是这种方式缺陷非常明显:
- 首先,每一次的
dispatch
操作,我们都需要在前面加上这样的逻辑代码; - 其次,存在大量重复的代码,会非常麻烦和臃肿;
是否有一种更优雅的方式来处理这样的相同逻辑呢?
- 我们可以将代码封装到一个独立的函数中
function dispatchAndLog(action) {console.log("dispatching:", action);store.dispatch(addAction(5));console.log("新的state:", store.getState());
}dispatchAndLog(addAction(10));
但是这样的代码有一个非常大的缺陷:
- 调用者(使用者)在使用我的
dispatch
时,必须使用我另外封装的一个函数dispatchAndLog
; - 显然,对于调用者来说,很难记住这样的API,更加习惯的方式是直接调用
dispatch
;
我们来进一步对代码进行优化;
2.2. 修改dispatch
事实上,我们可以利用一个hack一点的技术:Monkey Patching,利用它可以修改原有的程序逻辑;
我们对代码进行如下的修改:
let next = store.dispatch;function dispatchAndLog(action) {console.log("dispatching:", addAction(10));next(addAction(5));console.log("新的state:", store.getState());
}store.dispatch = dispatchAndLog;
- 这样就意味着我们已经直接修改了
dispatch
的调用过程; - 在调用
dispatch
的过程中,真正调用的函数其实是dispatchAndLog
;
当然,我们可以将它封装到一个模块中,只要调用这个模块中的函数,就可以对store
进行这样的处理:
function patchLogging(store) {let next = store.dispatch;function dispatchAndLog(action) {console.log("dispatching:", action);next(addAction(5));console.log("新的state:", store.getState());}store.dispatch = dispatchAndLog;
}
2.3. thunk需求
redux-thunk
的作用:
- 我们知道redux中利用一个中间件
redux-thunk
可以让我们的dispatch
不再只是处理对象,并且可以处理函数; - 那么
redux-thunk
中的基本实现过程是怎么样的呢?事实上非常的简单。
我们来看下面的代码:
function patchThunk(store) {let next = store.dispatch;function dispatchAndThunk(action) {if (typeof action === "function") {action(store.dispatch, store.getState);} else {next(action);}}store.dispatch = dispatchAndThunk;
}
- 我们又对
dispatch
进行转换,这个dispatch
会判断传入的
将两个patch
应用起来,进行测试:
patchLogging(store);
patchThunk(store);store.dispatch(addAction(10));function getData(dispatch) {setTimeout(() => {dispatch(subAction(10));}, 1000)
}// 传入函数
store.dispatch(getData);
2.4. 合并中间件
单个调用某个函数来合并中间件并不是特别的方便,我们可以封装一个函数来实现所有的中间件合并:
function applyMiddleware(store, middlewares) {middlewares = middlewares.slice();middlewares.forEach(middleware => {store.dispatch = middleware(store);})
}applyMiddleware(store, [patchLogging, patchThunk]);
我们来理解一下上面操作之后,代码的流程:
当然,真实的中间件实现起来会更加的灵活,这里我们仅仅做一个抛砖引玉,有兴趣可以参考redux合并中间件的源码流程。
相关文章:
【React系列】Redux(二)中间件
本文来自#React系列教程:https://mp.weixin.qq.com/mp/appmsgalbum?__bizMzg5MDAzNzkwNA&actiongetalbum&album_id1566025152667107329) 一. 中间件的使用 1.1. 组件中异步请求 在之前简单的案例中,redux中保存的counter是一个本地定义的数据…...
YOLOv8改进 | 2023Neck篇 | 利用Gold-YOLO改进YOLOv8对小目标检测
一、本文介绍 本文给大家带来的改进机制是Gold-YOLO利用其Neck改进v8的Neck,GoLd-YOLO引入了一种新的机制——信息聚集-分发(Gather-and-Distribute, GD)。这个机制通过全局融合不同层次的特征并将融合后的全局信息注入到各个层级中,从而实现更高效的信息交互和融合。这种…...
ubuntu环境安装配置nginx流程
今天分享ubuntu环境安装配置nginx流程 一、下载安装 1、检查是否已经安装 nginx -v 结果 2、安装 apt install nginx-core 过程 查看版本:nginx -v 安装路径:whereis nginx nginx文件安装完成之后的文件位置: /usr/sbin/nginx…...
【LMM 010】MiniGPT-v2:使用独特的标识符实现视觉语言多任务学习的统一的多模态大模型
论文标题:MiniGPT-v2: Large Language Model As a Unified Interface for Vision-Language Multi-task Learning 论文作者:Jun Chen, Deyao Zhu, Xiaoqian Shen, Xiang Li, Zechun Liu, Pengchuan Zhang, Raghuraman Krishnamoorthi, Vikas Chandra, Yun…...
人工智能如何重塑金融服务业
在体验优先的世界中识别金融服务业中的AI使用场景 人工智能(AI)作为主要行业的大型组织的重要业务驱动力,持续受到关注。众所周知,传统金融服务业在采用新技术方面相对滞后,一些组织使用的还是上世纪50年代和60年代发…...
Iterable 对象转换为 Stream 对象
在 Java 8 中,可以使用 Stream API 来对集合进行操作。要将 Iterable 对象转换为 Stream 对象,可以使用 StreamSupport 类的 stream() 方法。具体来说,可以按照以下步骤进行转换: 调用 Spliterators.spliteratorUnknownSize(iter…...
基于Java+SpringBoot+vue+elementUI私人健身教练预约管理系统设计实现
基于JavaSpringBootvueelementUI私人健身教练预约管理系统设计实现 欢迎点赞 收藏 ⭐留言 文末获取源码联系方式 文章目录 基于JavaSpringBootvueelementUI私人健身教练预约管理系统设计实现一、前言介绍:二、系统设计:2.1 性能需求分析2.2 B/S架构&…...
2024,启动(回顾我的2023)
零.前言 打开博客想写个年度总结,发现已经半年没有更新文章了,排名从几千掉到了几万,不过数据量还是不错的。 时间过得可真快,2023年是充满动荡的一年,上半年gpt横空出世,下半年各种翻车暴雷吃瓜吃到嘴软…...
Web网页开发-盒模型-笔记
1.CSS的三种显示方式 (1)块级元素:标签所占区域默认为一行 特点:一行一个 可设宽高 (2)行内元素:标签所占区域由内容顶开,行内元素无法使用text-align 特点:一行多个 不可设宽高,margin上下和padding上下都不能改变位…...
Java打成压缩包的方法汇总
文章目录 1.将指定目录下的文件打包成 .zip2.将指定目录下的文件打包成 .tar.gz3.将指定目录下的文件打包成 .tar4.将指定目录下的文件打包成 .rar5.生成若干个txt并打包到zip中 1.将指定目录下的文件打包成 .zip 代码示例: import java.io.*; import java.util.z…...
2023年第2季社区Task挑战赛贡献者榜单
基于FISCO BCOS及Weldentity,实现SSO单点登录服务;提供食品溯源、电商运费险7天退保、电子病历等智能合约库业务场景案例;基于FISCO BCOS更新游戏体验;体验并分析解读最新发布的分布式数据协作管理解决方案DDCMS,提供相…...
Clickhouse 为什么快
ClickHouse是一个用于联机分析处理(OLAP)的开源列式数据库管理系统(DBMS)。它之所以能提供出色的查询性能和处理速度,主要归功于以下几个方面的设计和优化: 列式存储 ClickHouse存储数据按列而不是按行组织…...
【React系列】react-router
本文来自#React系列教程:https://mp.weixin.qq.com/mp/appmsgalbum?__bizMzg5MDAzNzkwNA&actiongetalbum&album_id1566025152667107329) 一. 认识react-router 1.2. 前端路由原理 前端路由是如何做到URL和内容进行映射呢?监听URL的改变。 UR…...
[数据集][目标检测]车辆检测数据集VOC+YOLO格式1.6w张3类别
一共分为3个压缩包: 【车辆检测数据集AVOCYOLO格式5423张3类别】 数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):5423 标注数…...
FindMy技术用于鼠标
鼠标是计算机的标准配置之一,其设计初衷是为了使计算机的操作更加简便快捷,减少用户在操作中的负担。用户可以通过移动鼠标,实现光标的精确移动,进而选择、拖拽、复制、粘贴等操作。这种操作方式,使得计算机的操作变得…...
已解决‘ping‘ 不是内部或外部命令,也不是可运行的程序或批处理文件。”的问题
已解决‘ping‘ 不是内部或外部命令,也不是可运行的程序或批处理文件。”的问题 文章目录 问题介绍 问题分析 解决思路 解决方法 检查并修复环境变量 进入c:\windows\system32再ping 使用系统工具修复系统文件 Q1 - 问题介绍 当您尝试在Windows命令提示符下…...
基于PGPGPOOL-II部署PostgreSQL高可用环境
PGPOOL-II是一个位于PostgreSQL服务器和 PostgreSQL 数据库客户端之间的中间件,具有以下功能: 1. 连接池:PGPOOL-II可以保持已经连接到 PostgreSQL 服务器的连接,并在使用相同参数(例如:用户名、数据库、协议版本)连接进来时重用它们。这可以减少连接开销,并增加系统的…...
【大数据进阶第二阶段之Hadoop学习笔记】Hadoop 运行环境搭建
【大数据进阶第二阶段之Hadoop学习笔记】Hadoop 概述-CSDN博客 【大数据进阶第二阶段之Hadoop学习笔记】Hadoop 运行环境搭建-CSDN博客 【大数据进阶第二阶段之Hadoop学习笔记】Hadoop 运行模式-CSDN博客 1、模板虚拟机环境准备 1.1、 hadoop100 虚拟机配置要求如下 &…...
Python 操作 JMeter 探索:pymeter 实操指南
概要 JMeter 是一个流行的性能测试工具,用于测试 Web 应用程序的性能和负载。它通常与 GUI 一起使用,但如果您想在自动化测试中集成 JMeter,或者以编程方式创建和运行测试计划,那么 pymeter 库将是一个强大的工具。本文将介绍如何…...
微软 Power Platform 使用Power Automate发送邮件以Dataverse作为数据源的附件File Column
微软Power Platform使用Power Automate发送邮件添加Power Apps以Dataverse作为数据源的附件File Column方式 目录 微软Power Platform使用Power Automate发送邮件添加Power Apps以Dataverse作为数据源的附件File Column方式1、需求背景介绍2、附件列File Column介绍3、如何在Po…...
雾天条件下 SLS 融合网络的三维目标检测
论文地址:3D Object Detection with SLS-Fusion Network in Foggy Weather Conditions 论文代码:https://github.com/maiminh1996/SLS-Fusion 论文摘要 摄像头或激光雷达(光检测和测距)等传感器的作用对于自动驾驶汽车的环境意识…...
在pycharm中执行 os.makedirs 提示用户名或密码不正确
问题:在pycharm中运行脚本,在 \10.0.21.249\share 共享目录下创建目录提示错误 发现:手动在该目录下创建目录没有问题。 解决方法: 切换到cmd 命令行运行该脚本成功创建 猜测:感觉应该是pycharm中使用的用户名和密码存…...
使用Go语言编写高效的HTTP服务器
随着互联网的快速发展,HTTP服务器在Web开发中扮演着越来越重要的角色。而Go语言作为一种高效、并发性强的编程语言,为编写高性能的HTTP服务器提供了强大的支持。本文将探讨如何使用Go语言编写高效的HTTP服务器。 首先,我们需要了解Go语言的H…...
代码随想录day20 开始二叉搜索树
654.最大二叉树 题目 给定一个不含重复元素的整数数组。一个以此数组构建的最大二叉树定义如下: 二叉树的根是数组中的最大元素。左子树是通过数组中最大值左边部分构造出的最大二叉树。右子树是通过数组中最大值右边部分构造出的最大二叉树。 通过给定的数组构…...
从0开始python学习-39.requsts库
目录 HTTP协议 1. 请求 2. 响应 Requests库 1. 安装 2. 请求方式 2.1 requests.请求方式(参数) 2.2 requests.request() 2.3 requests.session().request() 2.4 三种方式之间的关联 3. 请求参数 3.1 params:查询字符串参数 3.2 data:Form表单…...
【面试高频算法解析】算法练习3 双指针
前言 本专栏旨在通过分类学习算法,使您能够牢固掌握不同算法的理论要点。通过策略性地练习精选的经典题目,帮助您深度理解每种算法,避免出现刷了很多算法题,还是一知半解的状态 专栏导航 二分查找回溯双指针滑动窗口深度优先搜索…...
React16源码: Why16, 研究源码的意义, 源码目录核心结构分析
为什么要选择React16 现在React18都早已实践很多,为何回过头来看16版本的代码理由如下 从实际出发,企业内老旧项目多为16版本,理解16的核心能够帮助我们快速解决问题16版本React是完全重写了核心代码, 是一次重大的更新 引入了 fiber 这个概…...
mybatis-flex笔记
MyBatis-Flex 的增删改功能 - MyBatis-Flex 官方网站https://mybatis-flex.com/zh/base/add-delete-update.html 代码https://gitee.com/hntianshu/mybatis-flex-test 一 新增数据 不忽略 null 值。 就是允许有null 忽略null 就是不允许有null BaseMapper 的接口提供了 inser…...
Debezium发布历史47
原文地址: https://debezium.io/blog/2019/02/13/debezium-0-9-1-final-released/ 欢迎关注留言,我是收集整理小能手,工具翻译,仅供参考,笔芯笔芯. Debezium 0.9.1.Final 发布 二月 13, 2019 作者: Gunna…...
Python爬虫抓包常见问题解决
对于Python爬虫和Fiddler抓包,可能遇到的问题及解决: 代理设置错误:如果你在使用Python爬虫时遇到抓不到包的问题,首先应该检查你的浏览器代理设置是否正确。以Chrome为例,代理设置为:右上角菜单按钮>设…...
西安政府部门政府网站建设服务商/中国十大企业管理培训机构
CSS3规范中对背景这一部分,新加入了一些令人兴奋的功能,如可以设置多个背景图片、可以指定背景大小、设置背景渐变等功能。CSS3规范中定义的背景属性有: 属性名可能的值默认值background是一种简写方式:bg-image || bg-position |…...
wordpress教程 知乎/电商网站设计论文
一.Function函数基础 函数:就是将一些语句进行封装,然后通过调用的形式,执行这些语句。 1.函数的作用: 将大量重复的语句写在函数里,以后需要这些语句的时候,可以直接调用函数,避免重复劳动。 …...
网站模块是指什么地方/交换链接营销的典型案例
1.选中项目后选择 open in Terminal 2.1键入指令:mvn clean install -Dmaven.test.skiptrue 2.2或者通过maven打包 指令 clean package -Dmaven.test.skiptrue 3.会在存放项目的target下生成项目的jar文件 4.在输入框输入cmd 5.windos在黑窗口下输入指令&#x…...
网站开发一般多钱/天津seo推广软件
All objects on the heap contain two overhead members: the type object pointer and the sync block index.转载于:https://www.cnblogs.com/zhtf2014/archive/2011/07/29/2121594.html...
南通物流网站建设/网络营销文案实例
URL即:统一资源定位符 (Uniform Resource Locator, URL) 完整的URL由这几个部分构成: scheme://host:port/path?query#fragment scheme:通信协议 常用的http,ftp,maito等 host:主机 服务器(计算机)域名系统 (DNS) 主机名或 IP 地址。 port:端口号 整数,…...
做网站要服务器吗/seo研究协会
说明:操作系统:CentOS 6.5 64位需求:编译安装LAMP运行环境各软件版本如下:MySQL:mysql-5.1.73Apache:httpd-2.2.31PHP:php-5.2.17具体操作:准备篇一、配置防火墙,开启80端…...