React-代码复用(mixin.hoc.render props)
前言
最近在学习React的封装,虽然日常的开发中也有用到HOC或者Render Props,但从继承到组合,静态构建到动态渲染,都是似懂非懂,索性花时间系统性的整理,如有错误,请轻喷~~
例子
以下是React官方的一个例子,我会采用不同的封装方法来尝试代码复用,例子地址。
组件在 React 是主要的代码复用单元,但如何共享状态或一个组件的行为封装到其他需要相同状态的组件中并不是很明了
。
例如,下面的组件在 web 应用追踪鼠标位置:
class MouseTracker extends React.Component {
constructor(props) {
super(props);
this.handleMouseMove = this.handleMouseMove.bind(this);
this.state = { x: 0, y: 0 };
}
handleMouseMove(event) {
this.setState({
x: event.clientX,
y: event.clientY
});
}
render() {
return (
<div style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>
<h1>Move the mouse around!</h1>
<p>The current mouse position is ({this.state.x}, {this.state.y})</p>
</div>
);
}
}
随着鼠标在屏幕上移动,在一个
的组件上显示它的 (x, y) 坐标。
现在的问题是:我们如何在另一个组件中重用行为?换句话说,若另一组件需要知道鼠标位置,我们能否封装这一行为以让能够容易在组件间共享?
由于组件是 React 中最基础的代码重用单元
,现在尝试重构一部分代码能够在 组件中封装我们需要在其他地方的行为。
// The <Mouse> component encapsulates the behavior we need...
class Mouse extends React.Component {
constructor(props) {
super(props);
this.handleMouseMove = this.handleMouseMove.bind(this);
this.state = { x: 0, y: 0 };
}
handleMouseMove(event) {
this.setState({
x: event.clientX,
y: event.clientY
});
}
render() {
return (
<div style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>
{/* ...but how do we render something other than a <p>? */}
<p>The current mouse position is ({this.state.x}, {this.state.y})</p>
</div>
);
}
}
class MouseTracker extends React.Component {
render() {
return (
<div>
<h1>Move the mouse around!</h1>
<Mouse />
</div>
);
}
}
现在 组件封装了所有关于监听 mousemove 事件和存储鼠标 (x, y) 位置的行为,但其仍不失真正的可重用。
例如,假设我们现在有一个在屏幕上跟随鼠标渲染一张猫的图片的 组件。我们可能使用 <Cat mouse={{ x, y }} prop 来告诉组件鼠标的坐标以让它知道图片应该在屏幕哪个位置。
首先,你可能会像这样,尝试在 的内部的渲染方法 渲染 组件:
class Cat extends React.Component {
render() {
const mouse = this.props.mouse
return (
<img src="/cat.jpg" style={{ position: 'absolute', left: mouse.x, top: mouse.y }} />
);
}
}
class MouseWithCat extends React.Component {
constructor(props) {
super(props);
this.handleMouseMove = this.handleMouseMove.bind(this);
this.state = { x: 0, y: 0 };
}
handleMouseMove(event) {
this.setState({
x: event.clientX,
y: event.clientY
});
}
render() {
return (
<div style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>
{/*
We could just swap out the <p> for a <Cat> here ... but then
we would need to create a separate <MouseWithSomethingElse>
component every time we need to use it, so <MouseWithCat>
isn't really reusable yet.
*/}
<Cat mouse={this.state} />
</div>
);
}
}
class MouseTracker extends React.Component {
render() {
return (
<div>
<h1>Move the mouse around!</h1>
<MouseWithCat />
</div>
);
}
}
这一方法对我们的具体用例来说能够生效,但我们却没法实现真正的将行为封装成可重用的方式的目标。现在,每次我们在不同的用例中想要使用鼠标的位置,我们就不得不创建一个新的针对那一用例渲染不同内容的组件 (如另一个关键的 <MouseWithCat>)
。
Mixin
Mixin概念
React Mixin将通用共享的方法包装成Mixins方法,然后注入各个组件实现,事实上已经是不被官方推荐使用
了,但仍然可以学习一下,了解其为什么被遗弃,先从API看起。
React Mixin只能通过React.createClass()使用, 如下:
var mixinDefaultProps = {}
var ExampleComponent = React.createClass({
mixins: [mixinDefaultProps],
render: function(){}
});
Mixin实现
// 封装的Mixin
const mouseMixin = {
getInitialState() {
return {
x: 0,
y: 0
}
},
handleMouseMove(event) {
this.setState({
x: event.clientX,
y: event.clientY
})
}
}
const Mouse = createReactClass({
mixins: [mouseMixin],
render() {
return (
<div style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>
<p>The current mouse position is ({this.state.x}, {this.state.y})</p>
</div>
)
}
})
const Cat = createReactClass({
mixins: [mouseMixin],
render() {
return (
<div style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>
<img src="/cat.jpg" style={{ position: 'absolute', left: this.state.x, top: this.state.y }} alt="" />
</div>
)
}
})
Mixin的问题
然而,为什么Mixin会被不推荐使用?归纳起来就是以下三点
1. Mixin引入了隐式依赖关系 如:
你可能会写一个有状态的组件,然后你的同事可能会添加一个读取这个状态的mixin。在几个月内,您可能需要将该状态移至父组件,以便与兄弟组件共享。你会记得更新mixin来读取道具吗?如果现在其他组件也使用这个mixin呢?
2. Mixin导致名称冲突 如:
你在该Mixin定义了getSomeName, 另外一个Mixin又定义了同样的名称getSomeName, 造成了冲突。
3. Mixin导致复杂的滚雪球
随着时间和业务的增长, 你对Mixin的修改越来越多, 到最后会变成一个难以维护的Mixin。
4. 拥抱ES6,ES6的class不支持Mixin
HOC
HOC概念
高阶组件(HOC)是react中的高级技术,用来重用组件逻辑。但高阶组件本身并不是React API。它只是一种模式,这种模式是由react自身的组合性质必然产生的,是React社区发展中产生的一种模式
。
高阶组件的名称是从高阶函数来的, 如果了解过函数式编程, 就会知道高阶函数就是一个入参是函数,返回也是函数的函数,那么高阶组件顾名思义,就是一个入参是组件,返回也是组件的函数
,如:
const EnhancedComponent = higherOrderComponent(WrappedComponent);
HOC实现
高阶组件在社区中, 有两种使用方式, 分别是:
其中 W (WrappedComponent) 指被包裹的 React.Component,E (EnhancedComponent) 指返回类型为 React.Component 的新的 HOC。
Props Proxy
: HOC 对传给 WrappedComponent W 的 porps 进行操作。Inheritance Inversion
: HOC 继承 WrappedComponent W。
依然是使用之前的例子, 先从比较普通使用的Props Proxy
看起:
class Mouse extends React.Component {
render() {
const { x, y } = this.props.mouse
return (
<p>The current mouse position is ({x}, {y})</p>
)
}
}
class Cat extends React.Component {
render() {
const { x, y } = this.props.mouse
return (
<img src="/cat.jpg" style={{ position: 'absolute', left: x, top: y }} alt="" />
)
}
}
const MouseHoc = (MouseComponent) => {
return class extends React.Component {
constructor(props) {
super(props)
this.handleMouseMove = this.handleMouseMove.bind(this)
this.state = { x: 0, y: 0 }
}
handleMouseMove(event) {
this.setState({
x: event.clientX,
y: event.clientY
})
}
render() {
return (
<div style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>
<MouseComponent mouse={this.state} />
</div>
)
}
}
}
const EnhanceMouse = MouseHoc(Mouse)
const EnhanceCat = MouseHoc(Cat)
那么在Hoc的Props Proxy模式下, 我们可以做什么?
操作Props
如上面的MouseHoc, 假设在日常开发中,我们需要传入一个props给Mouse或者Cat,那么我们可以在HOC里面对props进行增删查改
等操作,如下:
const MouseHoc = (MouseComponent, props) => {
props.text = props.text + '---I can operate props'
return class extends React.Component {
......
render() {
return (
<div style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>
<MouseComponent {...props} mouse={this.state} />
</div>
)
}
}
}
MouseHoc(Mouse, {
text: 'some thing...'
})
通过 Refs 访问组件实例
function refsHOC(WrappedComponent) {
return class RefsHOC extends React.Component {
proc(wrappedComponentInstance) {
wrappedComponentInstance.method()
}
render() {
const props = Object.assign({}, this.props, {ref: this.proc.bind(this)})
return <WrappedComponent {...props}/>
}
}
}
提取state
就是我们的例子。
<MouseComponent mouse={this.state} />
包裹 WrappedComponent
<div style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>
<MouseComponent mouse={this.state} />
</div>
另外一种HOC模式则是Inheritance Inversion
,不过该模式比较少见,一个最简单的例子如下:
function iiHOC(WrappedComponent) {
return class Enhancer extends WrappedComponent {
render() {
return super.render()
}
}
}
你可以看到,返回的 HOC 类(Enhancer)继承了 WrappedComponent。之所以被称为 Inheritance Inversion 是因为 WrappedComponent 被 Enhancer 继承了,而不是 WrappedComponent 继承了 Enhancer。在这种方式中,它们的关系看上去被反转(inverse)了。Inheritance Inversion 允许
HOC 通过 this 访问到 WrappedComponent,意味着它可以访问到 state、props、组件生命周期方法和 render 方法
。
那么在我们的例子中它是这样的:
class Mouse extends React.Component {
render(props) {
const { x, y } = props.mouse
return (
<p>The current mouse position is ({x}, {y})</p>
)
}
}
class Cat extends React.Component {
render(props) {
const { x, y } = props.mouse
return (
<img src="/cat.jpg" style={{ position: 'absolute', left: x, top: y }} alt="" />
)
}
}
const MouseHoc = (MouseComponent) => {
return class extends MouseComponent {
constructor(props) {
super(props)
this.handleMouseMove = this.handleMouseMove.bind(this)
this.state = { x: 0, y: 0 }
}
handleMouseMove(event) {
this.setState({
x: event.clientX,
y: event.clientY
})
}
render() {
const props = {
mouse: this.state
}
return (
<div style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>
{super.render(props)}
</div>
)
}
}
}
const EnhanceMouse = MouseHoc(Mouse)
const EnhanceCat = MouseHoc(Cat)
同样, 在II模式下,我们能做些什么呢?
渲染劫持
因为render()返回的就是JSX编译后的对象,如下:
可以通过手动修改这个tree,来达到一些需求效果,不过这通常不会用到:
function iiHOC(WrappedComponent) {
return class Enhancer extends WrappedComponent {
render() {
const elementsTree = super.render()
let newProps = {};
if (elementsTree && elementsTree.type === 'input') {
newProps = {value: 'may the force be with you'}
}
const props = Object.assign({}, elementsTree.props, newProps)
const newElementsTree = React.cloneElement(elementsTree, props, elementsTree.props.children)
return newElementsTree
}
}
}
操作 state
HOC 可以读取、编辑和删除 WrappedComponent 实例的 state,如果你需要,你也可以给它添加更多的 state。记住,这会搞乱 WrappedComponent 的 state,导致你可能会破坏某些东西。要限制 HOC 读取或添加 state,添加 state 时应该放在单独的命名空间里,而不是和 WrappedComponent 的 state 混在一起。
export function IIHOCDEBUGGER(WrappedComponent) {
return class II extends WrappedComponent {
render() {
return (
<div>
<h2>HOC Debugger Component</h2>
<p>Props</p> <pre>{JSON.stringify(this.props, null, 2)}</pre>
<p>State</p><pre>{JSON.stringify(this.state, null, 2)}</pre>
{super.render()}
</div>
)
}
}
}
为什么有Class而不去使用继承返回来使用HOC
可能有人看到这里会有疑惑,为什么有Class而不去使用继承返回来使用HOC
, 这里推荐知乎的一个比较好的答案
OOP和FP并不矛盾,所以混着用没毛病,很多基于FP思想的库也需要OOP来搭建。
为什么React推崇HOC和组合的方式,我的理解是React希望组件是按照最小可用的思想来进行封装的,理想的说,就是一个组件只做一件的事情,且把它做好,DRY。在OOP原则,这叫单一职责原则。如果要对组件增强,首先应该先思路这个增强的组件需要用到哪些功能,这些功能由哪些组件提供,然后把这些组件组合起来.
D中A相关的功能交由D内部的A来负责,D中B相关的功能交由D内部的B来负责,D仅仅负责维护A,B,C的关系,另外也可以额外提供增加项,实现组件的增强。
继承没有什么不好,注意,React只是推荐,但没限制。其实用继承来扩展组件也没问题,而且也存在这样的场景。比如:有一个按钮组件,仅仅是对Button进行一个包装,我们且叫它Button,可是,按照产品需求,很多地方的按钮都是带着一个icon的,我们需要提供一个IconButton。这是时候,就可以通过继承来扩展,同时组合另外一个独立的组件,我们且叫它Icon,显示icon的功能交给Icon组件来做,原来按钮的功能继续延续着。对于这种同类型组件的扩展,我认为用继承的方式是没关系的,灵活性,复用性还在。
但是,用继承的方式扩展前,要先思考,新组件是否与被继承的组件是不是同一类型的,同一类职责的。如果是,可以继承,如果不是,那么就用组合。怎么定义同一类呢,回到上面的Button的例子,所谓同一类,就是说,我直接用IconButton直接替换掉Button,不去改动其他代码,页面依然可以正常渲染,功能可以正常使用,就可以认为是同一类的,在OOP中,这叫做里氏替换原则。继承会带来什么问题,以我的实践经验,过渡使用继承,虽然给编码带来便利,但容易导致代码失控,组件膨胀,降低组件的复用性。比如:有一个列表组件,叫它ListView吧,可以上下滚动显示一个item集,突然有一天需求变了,PM说,我要这个ListView能像iOS那样有个回弹效果。好,用继承对这个ListView进行扩展,加入了回弹效果,任务closed。第二天PM找上门来了,希望所有上下滚动的地方都可以支持回弹效果,这时候就懵逼啦,怎么办?把ListView中回弹效果的代码copy一遍?这就和DRY原则相悖了不是,而且有可能受到其他地方代码的影响,处理回弹效果略有不同,要是有一天PM希望对这个回弹效果做升级,那就有得改啦。应对这种场景,最好的办法是啥?用组合,封装一个带回弹效果的Scroller,ListView看成是Scroller和item容器组件的组合,其他地方需要要用到滚动的,直接套一个Scroller,以后不管回弹效果怎么变,我只要维护这个Scroller就好了。当然,最理想的,把回弹效果也做成一个组件SpringBackEffect,从Scroller分离出来,这样,需要用回弹效果的地方就加上SpringBackEffect组件就好了,这就是为什么组合优先于继承的原因。
页面简单的时候,组合也好,继承也罢,可维护就好,能够快速的响应需求迭代就好,用什么方式实现到无所谓。但如果是一个大项目,页面用到很多组件,或者是团队多人共同维护的话,就要考虑协作中可能存在的矛盾,然后通过一定约束来闭坑。组合的方式是可以保证组件具有充分的复用性,灵活度,遵守DRY原则的其中一种实践。
Mixin和HOC的对比
Mixin就像他的名字,他混入了组件中
,我们很难去对一个混入了多个Mixin的组件进行管理,好比一个盒子,我们在盒子里面塞入了各种东西(功能),最后肯定是难以理清其中的脉络。
HOC则像是一个装饰器
,他是在盒子的外面一层一层的装饰,当我们想要抽取某一层或者增加某一层都非常容易。
HOC的约定
贯穿传递不相关props属性给被包裹的组件
高阶组件应该贯穿传递与它专门关注无关的props属性。
render() {
// 过滤掉专用于这个阶组件的props属性,
// 不应该被贯穿传递
const { extraProp, ...passThroughProps } = this.props;
// 向被包裹的组件注入props属性,这些一般都是状态值或
// 实例方法
const injectedProp = someStateOrInstanceMethod;
// 向被包裹的组件传递props属性
return (
<WrappedComponent
injectedProp={injectedProp}
{...passThroughProps}
/>
);
}
最大化的组合性
// 不要这样做……
const EnhancedComponent = withRouter(connect(commentSelector)(WrappedComponent))
// ……你可以使用一个函数组合工具
// compose(f, g, h) 和 (...args) => f(g(h(...args)))是一样的
const enhance = compose(
// 这些都是单独一个参数的高阶组件
withRouter,
connect(commentSelector)
)
const EnhancedComponent = enhance(WrappedComponent)
包装显示名字以便于调试
最常用的技术是包裹显示名字给被包裹的组件。所以,如果你的高阶组件名字是 withSubscription,且被包裹的组件的显示名字是 CommentList,那么就是用 WithSubscription(CommentList)这样的显示名字
function withSubscription(WrappedComponent) {
class WithSubscription extends React.Component {/* ... */}
WithSubscription.displayName = `WithSubscription(${getDisplayName(WrappedComponent)})`;
return WithSubscription;
}
function getDisplayName(WrappedComponent) {
return WrappedComponent.displayName || WrappedComponent.name || 'Component';
}
HOC的警戒
- 不要在render方法内使用高阶组件,因为每次高阶组件返回的都是不同的组件,会造成不必要的渲染。
- 必须将静态方法做拷贝。
HOC带来的问题:
- 当存在多个HOC时,你不知道Props是从哪里来的。
- 和Mixin一样, 存在相同名称的props,则存在覆盖问题,而且react并不会报错。
- JSX层次中多了很多层次(即无用的空组件),不利于调试。
- HOC属于静态构建,静态构建即是重新生成一个组件,即返回的新组件,不会马上渲染,即新组件中定义的生命周期函数只有新组件被渲染时才会执行。
Render Props
Render Props概念
Render Props从名知义,也是一种剥离重复使用的逻辑代码,提升组件复用性的解决方案。在被复用的组件中,
通过一个名为“render”(属性名也可以不是render,只要值是一个函数即可)的属性,该属性是一个函数,这个函数接受一个对象并返回一个子组件,会将这个函数参数中的对象作为props传入给新生成的组件。
Render Props应用
可以看下最初的例子在render props中的应用:
class Cat extends React.Component {
render() {
const mouse = this.props.mouse;
return (
<img src="/cat.jpg" style={{ position: 'absolute', left: mouse.x, top: mouse.y }} />
);
}
}
class Mouse extends React.Component {
constructor(props) {
super(props);
this.handleMouseMove = this.handleMouseMove.bind(this);
this.state = { x: 0, y: 0 };
}
handleMouseMove(event) {
this.setState({
x: event.clientX,
y: event.clientY
});
}
render() {
return (
<div style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>
{/*
Instead of providing a static representation of what <Mouse> renders,
use the `render` prop to dynamically determine what to render.
*/}
{this.props.render(this.state)}
</div>
);
}
}
class MouseTracker extends React.Component {
render() {
return (
<div>
<h1>Move the mouse around!</h1>
<Mouse render={mouse => (
<Cat mouse={mouse} />
)}/>
</div>
);
}
}
render props的优势
- 不用担心Props是从哪里来的, 它只能从父组件传递过来。
- 不用担心props的命名问题。
- render props是动态构建的。
动态构建和静态构建
这里简单的说下动态构建,因为React官方推崇动态组合
,然而HOC实际上是一个静态构建,比如,在某个需求下,我们需要根据Mouse中某个字段来决定渲染Cat组件或者Dog组件,使用HOC会是如下:
const MouseHoc = (Component) => {
return Class extends React.Component {
render() {
return (
<div>
<h1>Move the mouse around!</h1>
{
isCat ? <Cat mouse={mouse} /> : <Dog mouse={mouse} />
}
</div>
);
}
}
}
可以看到,我们不得不提前静态构建好Cat和Dog组件
假如我们用Render props:
class MouseTracker extends React.Component {
render() {
return (
<div>
<h1>Move the mouse around!</h1>
<Mouse render={(mouse, isCat) => (
isCat ? <Cat mouse={mouse} /> : <Dog mouse={mouse} />
)}/>
</div>
);
}
}
很明显,在动态构建的时候,我们具有更多的灵活性,我们可以更好的利用生命周期
,相比较HOC,就不得不引入Cat和Dog组件,污染了MouseHoc。
Render Props的缺点
无法使用SCU做优化, 具体参考官方文档。
总结
抛开被遗弃的Mixin和尚未稳定的Hooks,目前社区的代码复用方案主要还是HOC和Render Props,个人感觉,如果是多层组合或者需要动态渲染那就选择Render Props,而如果是诸如在每个View都要执行的简单操作,如埋点、title设置等或者是对性能要求比较高如大量表单可以采用HOC。
参考
Function as Child Components Not HOCs
React高阶组件和render props的适用场景有区别吗,还是更多的是个人偏好?
深入理解 React 高阶组件
高阶组件-React
精读《我不再使用高阶组件》
为什么 React 推崇 HOC 和组合的方式,而不是继承的方式来扩展组件?
React 中的 Render Props
使用 Render props 吧!
渲染属性(Render Props)
React-代码复用(mixin.hoc.render props)的更多相关文章
- React高阶组件 和 Render Props
高阶组件 本质 本质是函数,将组件作为接收参数,返回一个新的组件.HOC本身不是React API,是一种基于React组合的特而形成的设计模式. 解决的问题(作用) 一句话概括:功能的复用,减少代码 ...
- 学习React系列(十)——Render Props
解决问题:将行为封装,供多个组件使用(在多个组件之间分享某段代码) 组件中的props属性中包含一个"render"属性(该属性为一个返回值为元素的方法),然后在该组件的rende ...
- [React] Use Prop Collections with Render Props
Sometimes you have common use cases that require common props to be applied to certain elements. You ...
- 可复用 React 的 HOC 以及的 Render Props
重复是不可能的,这辈子都不可能写重复的代码 当然,这句话分分钟都要被产品(领导)打脸,真的最后一次改需求,我们烦恼于频繁修改的需求 虽然我们不能改变别人,但我们却可以尝试去做的更好,我们需要抽象,封装 ...
- React 代码共享最佳实践方式
任何一个项目发展到一定复杂性的时候,必然会面临逻辑复用的问题.在React中实现逻辑复用通常有以下几种方式:Mixin.高阶组件(HOC).修饰器(decorator).Render Props.Ho ...
- React中render Props模式
React组件复用 React组件复用的方式有两种: 1.render Props模式 2.高阶组件HOC 上面说的这两种方式并不是新的APi. 而是利用Raect自身的编码特点,演化而来的固定编码写 ...
- React Render Props 模式
概述 Render Props模式是一种非常灵活复用性非常高的模式,它可以把特定行为或功能封装成一个组件,提供给其他组件使用让其他组件拥有这样的能力,接下来我们一步一步来看React组件中如何实现这样 ...
- React 之 render props 的理解
1.基本概念 在调用组件时,引入一个函数类型的 prop,这个 prop定义了组件的渲染方式. 2.回调渲染 回顾组件通信的几种方式 父-> 子 props 子-> 父 回调.消息通道 任 ...
- [Recompose] Refactor React Render Props to Streaming Props with RxJS and Recompose
This lesson takes the concept of render props and migrates it over to streaming props by keeping the ...
随机推荐
- Java中的异常简介
Java中异常的分类 Java中的异常机制是针对正常运行程序的一个必要补充,一般来说没有加入异常机制,程序也能正常运营,但是,由于入参.程序逻辑的严谨度,总会有期望之外的结果生成,因此加入异常机制的补 ...
- 【爆料】-《西澳大学毕业证书》UWA一模一样原件
☞西澳大学毕业证书[微/Q:2544033233◆WeChat:CC6669834]UC毕业证书/联系人Alice[查看点击百度快照查看][留信网学历认证&博士&硕士&海归&a ...
- EffictiveC++笔记 第3章
Chapter 3 资源管理 条款13: 以对象管理资源 有时即使你顺利地写了对应对象的delete语句,但是前面的区域可能会有一个过早的return语句或者抛出了异常.它们一旦执行,控制流绝不会触及 ...
- 大白话5分钟带你走进人工智能-第十五节L1和L2正则几何解释和Ridge,Lasso,Elastic Net回归
第十五节L1和L2正则几何解释和Ridge,Lasso,Elastic Net回归 上一节中我们讲解了L1和L2正则的概念,知道了L1和L2都会使不重要的维度权重下降得多,重要的维度权重下降得少,引入 ...
- Apache Mina -2
我们可以了解到 mina是个异步通信框架,一般使用场景是服务端开发,长连接.异步通信使用mina是及其方便的.不多说,看例子. 本次mina 使用的例子是使用maven构建的,过程中需要用到的jar包 ...
- 审计篇丨PHPcms9.6.3后台XSS审计
引言 今天与大家分享的文章是关于审计思路的知识点,用到的是PHPcms的最新版本,因为常规扫描无法进入后台,所以我们修改了代码让扫描器爬虫爬到后台. 漏洞复现环境 安装PHPstudy 安装PHPcm ...
- c#发送邮件,可发送多个附件
1:创建SendMail类 2:调用方法 SendMail send = new SendMail("123456@qq.com", "123456@163.com&qu ...
- 如何高效的学习WEB前端
IT 行业的变化快是众人皆知的,需要持续去学习新的知识内容.但是,往往我们工作之后,经常发现学习的东西很少了,学习效率非常低,感觉自己到了一个瓶颈期,久而久之,就演变成『一年工作经验,重复去用十年』的 ...
- SAP MM 预留单据的历史修改记录?
SAP MM 预留单据的历史修改记录? 在笔者眼里,SAP系统是一个高度严谨的软件系统.用户在SAP系统里的相关操作,系统都会做记录.用户对于系统的相关单据的增删改,SAP系统都有保留change h ...
- ambari2.6.50 openssl 版本问题:SSLError: Failed to connect. Please check openssl library versions. Openssl error upon host registration
I'm trying to register hostnames in Ambari but getting the error below. We tried to run yum update o ...