实体对象:

import java.io.Serializable;

public class TranslatorData implements Serializable {

	private static final long serialVersionUID = 8763561286199081881L;

	private String id;
private String name;
private String message; //传输消息体内容 public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}

  

import com.bfxy.codec.MarshallingCodeCFactory;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.AdaptiveRecvByteBufAllocator;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler; public class NettyServer { public NettyServer() {
//1. 创建两个工作线程组: 一个用于接受网络请求的线程组. 另一个用于实际处理业务的线程组
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workGroup = new NioEventLoopGroup(); //2 辅助类
ServerBootstrap serverBootstrap = new ServerBootstrap();
try {
serverBootstrap.group(bossGroup, workGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024)
//表示缓存区动态调配(自适应)
.option(ChannelOption.RCVBUF_ALLOCATOR, AdaptiveRecvByteBufAllocator.DEFAULT)
//缓存区 池化操作
.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
//日志
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel sc) throws Exception {
//向管道中添加拦截器
sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder());
sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder());
sc.pipeline().addLast(new ServerHandler());
}
});
//绑定端口,同步等等请求连接
ChannelFuture cf = serverBootstrap.bind(8765).sync();
System.err.println("Server Startup...");
cf.channel().closeFuture().sync(); } catch (InterruptedException e) {
e.printStackTrace();
} finally {
//优雅停机
bossGroup.shutdownGracefully();
workGroup.shutdownGracefully();
System.err.println("Sever ShutDown...");
}
}
}

  

import com.bfxy.disruptor.MessageProducer;
import com.bfxy.disruptor.RingBufferWorkerPoolFactory;
import com.bfxy.entity.TranslatorData; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter; public class ServerHandler extends ChannelInboundHandlerAdapter { @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
/**
TranslatorData request = (TranslatorData)msg;
System.err.println("Sever端: id= " + request.getId()
+ ", name= " + request.getName()
+ ", message= " + request.getMessage());
//数据库持久化操作 IO读写 ---> 交给一个线程池 去异步的调用执行
TranslatorData response = new TranslatorData();
response.setId("resp: " + request.getId());
response.setName("resp: " + request.getName());
response.setMessage("resp: " + request.getMessage());
//写出response响应信息:
ctx.writeAndFlush(response);
*/
TranslatorData request = (TranslatorData)msg;
//自已的应用服务应该有一个ID生成规则
String producerId = "code:sessionId:001";
MessageProducer messageProducer = RingBufferWorkerPoolFactory.getInstance().getMessageProducer(producerId);
messageProducer.onData(request, ctx); }
}

  

import com.bfxy.disruptor.MessageConsumer;
import com.bfxy.entity.TranslatorData;
import com.bfxy.entity.TranslatorDataWapper; import io.netty.channel.ChannelHandlerContext; public class MessageConsumerImpl4Server extends MessageConsumer { public MessageConsumerImpl4Server(String consumerId) {
super(consumerId);
} public void onEvent(TranslatorDataWapper event) throws Exception {
TranslatorData request = event.getData();
ChannelHandlerContext ctx = event.getCtx();
//1.业务处理逻辑:
System.err.println("Sever端: id= " + request.getId()
+ ", name= " + request.getName()
+ ", message= " + request.getMessage()); //2.回送响应信息:
TranslatorData response = new TranslatorData();
response.setId("resp: " + request.getId());
response.setName("resp: " + request.getName());
response.setMessage("resp: " + request.getMessage());
//写出response响应信息:
ctx.writeAndFlush(response);
}
}

  客户端:

import com.bfxy.codec.MarshallingCodeCFactory;
import com.bfxy.entity.TranslatorData; import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.AdaptiveRecvByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler; public class NettyClient { public static final String HOST = "127.0.0.1";
public static final int PORT = 8765; //扩展 完善 池化: ConcurrentHashMap<KEY -> String, Value -> Channel>
private Channel channel; //1. 创建工作线程组: 用于实际处理业务的线程组
private EventLoopGroup workGroup = new NioEventLoopGroup(); private ChannelFuture cf; public NettyClient() {
this.connect(HOST, PORT);
} private void connect(String host, int port) {
//2 辅助类(注意Client 和 Server 不一样)
Bootstrap bootstrap = new Bootstrap();
try { bootstrap.group(workGroup)
.channel(NioSocketChannel.class)
//表示缓存区动态调配(自适应)
.option(ChannelOption.RCVBUF_ALLOCATOR, AdaptiveRecvByteBufAllocator.DEFAULT)
//缓存区 池化操作
.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
.handler(new LoggingHandler(LogLevel.INFO))
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel sc) throws Exception {
sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder());
sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder());
sc.pipeline().addLast(new ClientHandler());
}
});
//绑定端口,同步等等请求连接
this.cf = bootstrap.connect(host, port).sync();
System.err.println("Client connected..."); //接下来就进行数据的发送, 但是首先我们要获取channel:
this.channel = cf.channel(); } catch (InterruptedException e) {
e.printStackTrace();
}
}
//发送数据
public void sendData(){
for(int i =0; i <10; i++){
TranslatorData request = new TranslatorData();
request.setId("" + i);
request.setName("请求消息名称 " + i);
request.setMessage("请求消息内容 " + i);
this.channel.writeAndFlush(request);
}
} public void close() throws Exception {
cf.channel().closeFuture().sync();
//优雅停机
workGroup.shutdownGracefully();
System.err.println("Sever ShutDown...");
}
}

  

vimport com.bfxy.disruptor.MessageProducer;
import com.bfxy.disruptor.RingBufferWorkerPoolFactory;
import com.bfxy.entity.TranslatorData; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.ReferenceCountUtil; public class ClientHandler extends ChannelInboundHandlerAdapter { public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { /**
try {
TranslatorData response = (TranslatorData)msg;
System.err.println("Client端: id= " + response.getId()
+ ", name= " + response.getName()
+ ", message= " + response.getMessage());
} finally {
//一定要注意 用完了缓存 要进行释放
ReferenceCountUtil.release(msg);
}
*/
TranslatorData response = (TranslatorData)msg;
String producerId = "code:seesionId:002";
MessageProducer messageProducer = RingBufferWorkerPoolFactory.getInstance().getMessageProducer(producerId);
messageProducer.onData(response, ctx);
}
}

  

import com.bfxy.disruptor.MessageConsumer;
import com.bfxy.entity.TranslatorData;
import com.bfxy.entity.TranslatorDataWapper; import io.netty.channel.ChannelHandlerContext;
import io.netty.util.ReferenceCountUtil; public class MessageConsumerImpl4Client extends MessageConsumer { public MessageConsumerImpl4Client(String consumerId) {
super(consumerId);
} public void onEvent(TranslatorDataWapper event) throws Exception {
TranslatorData response = event.getData();
ChannelHandlerContext ctx = event.getCtx();
//业务逻辑处理:
try {
System.err.println("Client端: id= " + response.getId()
+ ", name= " + response.getName()
+ ", message= " + response.getMessage());
} finally {
ReferenceCountUtil.release(response);
}
}
}

  

工厂类的封装:

import java.io.Serializable;

public class TranslatorData implements Serializable {

	private static final long serialVersionUID = 8763561286199081881L;

	private String id;
private String name;
private String message; //传输消息体内容 public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}

  

import io.netty.channel.ChannelHandlerContext;
//dis内部需要传输的对象
public class TranslatorDataWapper {
//实际的数据
private TranslatorData data;
//ctx对象
private ChannelHandlerContext ctx; public TranslatorData getData() {
return data;
} public void setData(TranslatorData data) {
this.data = data;
} public ChannelHandlerContext getCtx() {
return ctx;
} public void setCtx(ChannelHandlerContext ctx) {
this.ctx = ctx;
}
}

  

import com.bfxy.entity.TranslatorDataWapper;
import com.lmax.disruptor.WorkHandler;
//抽象的让子类实现
public abstract class MessageConsumer implements WorkHandler<TranslatorDataWapper> { protected String consumerId; public MessageConsumer(String consumerId) {
this.consumerId = consumerId;
} public String getConsumerId() {
return consumerId;
} public void setConsumerId(String consumerId) {
this.consumerId = consumerId;
}
}

  

import com.bfxy.entity.TranslatorData;
import com.bfxy.entity.TranslatorDataWapper;
import com.lmax.disruptor.RingBuffer; import io.netty.channel.ChannelHandlerContext; //生产者
public class MessageProducer { private String producerId; private RingBuffer<TranslatorDataWapper> ringBuffer; public MessageProducer(String producerId, RingBuffer<TranslatorDataWapper> ringBuffer) {
this.producerId = producerId;
this.ringBuffer = ringBuffer;
}
//发送实际的对象和ctx
public void onData(TranslatorData data, ChannelHandlerContext ctx) {
long sequence = ringBuffer.next();
try {
TranslatorDataWapper wapper = ringBuffer.get(sequence);
wapper.setData(data);
wapper.setCtx(ctx);
} finally {
ringBuffer.publish(sequence);
}
}
}

  

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import com.bfxy.entity.TranslatorDataWapper;
import com.lmax.disruptor.EventFactory;
import com.lmax.disruptor.ExceptionHandler;
import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.SequenceBarrier;
import com.lmax.disruptor.WaitStrategy;
import com.lmax.disruptor.WorkerPool;
import com.lmax.disruptor.dsl.ProducerType; //环形缓存工作池子工厂
public class RingBufferWorkerPoolFactory {
//静态内部类的单例模式
private static class SingletonHolder {
static final RingBufferWorkerPoolFactory instance = new RingBufferWorkerPoolFactory();
}
//对外不能暴露的接口
private RingBufferWorkerPoolFactory(){ }
//对外创建
public static RingBufferWorkerPoolFactory getInstance() {
return SingletonHolder.instance;
} //生产者池
private static Map<String, MessageProducer> producers = new ConcurrentHashMap<String, MessageProducer>();
//消费者池
private static Map<String, MessageConsumer> consumers = new ConcurrentHashMap<String, MessageConsumer>(); private RingBuffer<TranslatorDataWapper> ringBuffer; private SequenceBarrier sequenceBarrier; private WorkerPool<TranslatorDataWapper> workerPool; //ProducerType 生产者类型是多生产还是单生产
public void initAndStart(ProducerType type, int bufferSize, WaitStrategy waitStrategy, MessageConsumer[] messageConsumers) {
//1. 构建ringBuffer对象
this.ringBuffer = RingBuffer.create(type,
new EventFactory<TranslatorDataWapper>() {
public TranslatorDataWapper newInstance() {
return new TranslatorDataWapper();
}
},
bufferSize,
waitStrategy);
//2.设置序号栅栏
this.sequenceBarrier = this.ringBuffer.newBarrier(); //3.设置工作池
this.workerPool = new WorkerPool<TranslatorDataWapper>(
this.ringBuffer,
this.sequenceBarrier,
new EventExceptionHandler(), messageConsumers); //4 把所构建的消费者置入池中
for(MessageConsumer mc : messageConsumers){
this.consumers.put(mc.getConsumerId(), mc);
} //5 添加我们的sequences
this.ringBuffer.addGatingSequences(this.workerPool.getWorkerSequences()); //6 启动我们的工作池
this.workerPool.start(
Executors.newFixedThreadPool
(Runtime.getRuntime().availableProcessors()/2));
}
//生产者
public MessageProducer getMessageProducer(String producerId){
MessageProducer messageProducer = this.producers.get(
producerId);
if(null == messageProducer) {
messageProducer = new MessageProducer(producerId, this.ringBuffer);
this.producers.put(producerId, messageProducer);
}
return messageProducer;
} /**
* 异常静态类
*/
static class EventExceptionHandler implements ExceptionHandler<TranslatorDataWapper> {
public void handleEventException(Throwable ex, long sequence, TranslatorDataWapper event) {
} public void handleOnStartException(Throwable ex) {
} public void handleOnShutdownException(Throwable ex) {
}
}
}

  

import io.netty.handler.codec.marshalling.DefaultMarshallerProvider;
import io.netty.handler.codec.marshalling.DefaultUnmarshallerProvider;
import io.netty.handler.codec.marshalling.MarshallerProvider;
import io.netty.handler.codec.marshalling.MarshallingDecoder;
import io.netty.handler.codec.marshalling.MarshallingEncoder;
import io.netty.handler.codec.marshalling.UnmarshallerProvider;
import org.jboss.marshalling.MarshallerFactory;
import org.jboss.marshalling.Marshalling;
import org.jboss.marshalling.MarshallingConfiguration; /**
* Marshalling工厂
*/
public final class MarshallingCodeCFactory { /**
* 创建Jboss Marshalling解码器MarshallingDecoder
* @return MarshallingDecoder
*/
public static MarshallingDecoder buildMarshallingDecoder() {
//首先通过Marshalling工具类的精通方法获取Marshalling实例对象 参数serial标识创建的是java序列化工厂对象。
final MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("serial");
//创建了MarshallingConfiguration对象,配置了版本号为5
final MarshallingConfiguration configuration = new MarshallingConfiguration();
configuration.setVersion(5);
//根据marshallerFactory和configuration创建provider
UnmarshallerProvider provider = new DefaultUnmarshallerProvider(marshallerFactory, configuration);
//构建Netty的MarshallingDecoder对象,俩个参数分别为provider和单个消息序列化后的最大长度
MarshallingDecoder decoder = new MarshallingDecoder(provider, 1024 * 1024 * 1);
return decoder;
} /**
* 创建Jboss Marshalling编码器MarshallingEncoder
* @return MarshallingEncoder
*/
public static MarshallingEncoder buildMarshallingEncoder() {
final MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("serial");
final MarshallingConfiguration configuration = new MarshallingConfiguration();
configuration.setVersion(5);
MarshallerProvider provider = new DefaultMarshallerProvider(marshallerFactory, configuration);
//构建Netty的MarshallingEncoder对象,MarshallingEncoder用于实现序列化接口的POJO对象序列化为二进制数组
MarshallingEncoder encoder = new MarshallingEncoder(provider);
return encoder;
}
}

  生产者的逻辑:

import com.bfxy.disruptor.MessageConsumer;
import com.bfxy.entity.TranslatorData;
import com.bfxy.entity.TranslatorDataWapper;
import io.netty.channel.ChannelHandlerContext;
public class MessageConsumerImpl4Server extends MessageConsumer { public MessageConsumerImpl4Server(String consumerId) {
super(consumerId);
} public void onEvent(TranslatorDataWapper event) throws Exception {
TranslatorData request = event.getData();
ChannelHandlerContext ctx = event.getCtx();
//1.业务处理逻辑:
System.err.println("Sever端: id= " + request.getId()
+ ", name= " + request.getName()
+ ", message= " + request.getMessage()); //2.回送响应信息:
TranslatorData response = new TranslatorData();
response.setId("resp: " + request.getId());
response.setName("resp: " + request.getName());
response.setMessage("resp: " + request.getMessage());
//写出response响应信息:
ctx.writeAndFlush(response);
}
}

  消费者的逻辑:

import com.bfxy.disruptor.MessageConsumer;
import com.bfxy.entity.TranslatorData;
import com.bfxy.entity.TranslatorDataWapper;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.ReferenceCountUtil; public class MessageConsumerImpl4Client extends MessageConsumer { public MessageConsumerImpl4Client(String consumerId) {
super(consumerId);
} public void onEvent(TranslatorDataWapper event) throws Exception {
TranslatorData response = event.getData();
ChannelHandlerContext ctx = event.getCtx();
//业务逻辑处理:
try {
System.err.println("Client端: id= " + response.getId()
+ ", name= " + response.getName()
+ ", message= " + response.getMessage());
} finally {
ReferenceCountUtil.release(response);
}
}
}

  

import com.lmax.disruptor.dsl.ProducerType;

@SpringBootApplication
public class NettyServerApplication { public static void main(String[] args) {
SpringApplication.run(NettyServerApplication.class, args); MessageConsumer[] conusmers = new MessageConsumer[4];
for(int i =0; i < conusmers.length; i++) {
MessageConsumer messageConsumer = new MessageConsumerImpl4Server("code:serverId:" + i);
conusmers[i] = messageConsumer;
}
RingBufferWorkerPoolFactory.getInstance().initAndStart(ProducerType.MULTI,
1024*1024,
//new YieldingWaitStrategy(),
new BlockingWaitStrategy(),
conusmers); new NettyServer();
}
}

  

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import com.bfxy.client.MessageConsumerImpl4Client;
import com.bfxy.client.NettyClient;
import com.bfxy.disruptor.MessageConsumer;
import com.bfxy.disruptor.RingBufferWorkerPoolFactory;
import com.lmax.disruptor.BlockingWaitStrategy;
import com.lmax.disruptor.YieldingWaitStrategy;
import com.lmax.disruptor.dsl.ProducerType; @SpringBootApplication
public class NettyClientApplication { public static void main(String[] args) {
SpringApplication.run(NettyClientApplication.class, args); MessageConsumer[] conusmers = new MessageConsumer[4];
for(int i =0; i < conusmers.length; i++) {
MessageConsumer messageConsumer = new MessageConsumerImpl4Client("code:clientId:" + i);
conusmers[i] = messageConsumer;
}
RingBufferWorkerPoolFactory.getInstance().initAndStart(ProducerType.MULTI,
1024*1024,
//new YieldingWaitStrategy(),
new BlockingWaitStrategy(),
conusmers); //建立连接 并发送消息
new NettyClient().sendData();
}
}

  

Disruptor与Netty实现百万级(十)的更多相关文章

  1. Netty系列之Netty百万级推送服务设计要点

    1. 背景 1.1. 话题来源 最近很多从事移动互联网和物联网开发的同学给我发邮件或者微博私信我,咨询推送服务相关的问题.问题五花八门,在帮助大家答疑解惑的过程中,我也对问题进行了总结,大概可以归纳为 ...

  2. Netty_Netty系列之Netty百万级推送服务设计要点

    1. 背景 1.1. 话题来源 最近很多从事移动互联网和物联网开发的同学给我发邮件或者微博私信我,咨询推送服务相关的问题.问题五花八门,在帮助大家答疑解惑的过程中,我也对问题进行了总结,大概可以归纳为 ...

  3. 【netty】Netty系列之Netty百万级推送服务设计要点

    1. 背景 1.1. 话题来源 最近很多从事移动互联网和物联网开发的同学给我发邮件或者微博私信我,咨询推送服务相关的问题.问题五花八门,在帮助大家答疑解惑的过程中,我也对问题进行了总结,大概可以归纳为 ...

  4. Netty系列之Netty百万级推送服务设计要点(转)

    1. 背景 1.1. 话题来源 最近很多从事移动互联网和物联网开发的同学给我发邮件或者微博私信我,咨询推送服务相关的问题.问题五花八门,在帮助大家答疑解惑的过程中,我也对问题进行了总结,大概可以归纳为 ...

  5. Netty学习总结(3)——Netty百万级推送服务

    1. 背景 1.1. 话题来源 最近很多从事移动互联网和物联网开发的同学给我发邮件或者微博私信我,咨询推送服务相关的问题.问题五花八门,在帮助大家答疑解惑的过程中,我也对问题进行了总结,大概可以归纳为 ...

  6. Netty Redis 亿级流量 高并发 实战 (长文 修正版)

    目录 疯狂创客圈 Java 分布式聊天室[ 亿级流量]实战系列之 -30[ 博客园 总入口 ] 写在前面 1.1. 快速的能力提升,巨大的应用价值 1.1.1. 飞速提升能力,并且满足实际开发要求 1 ...

  7. 不仅仅是百万级TCP长连接框架 t-io

    t-io: 不仅仅是百万级TCP长连接框架 t-io是基于jdk aio实现的易学易用.稳定.性能强悍.将多线程运用到极致.内置功能丰富的即时通讯框架(广义上的即时通讯,并非指im),字母 t 寓意t ...

  8. MySQL 百万级分页优化

    MySQL 百万级分页优化 http://www.jb51.net/article/31868.htm 一般刚开始学SQL的时候,会这样写 : , ; 但在数据达到百万级的时候,这样写会慢死 : , ...

  9. MySQL 百万级分页优化(Mysql千万级快速分页)(转)

    http://www.jb51.net/article/31868.htm 以下分享一点我的经验 一般刚开始学SQL的时候,会这样写 复制代码 代码如下: SELECT * FROM table OR ...

随机推荐

  1. 「2019-8-11提高模拟赛」女装盛宴 (flag)

    传送门 Solution  基环树+倍增+双指针 第一次因为#define int long long而玄学RE 为什么标程都不用开\(long long\)啊 Code  /*玄学RE 看来defi ...

  2. CSP-S乱搞记

    还有一年的时间,没人能挡住我前进的脚步 以后不打算写游记了,补完这篇再写就等退役吧,不太想传播什么负能量,走这条路,希望能得到自己想要的东西 Day-n 上了一个月文化课,班主任突然催我搞竞赛??? ...

  3. dedecms 模板文件不存在,无法解析文档的终极各种解决办法

    dedecms 模板文件不存在,无法解析文档"的终极各种解决办法 方法一:[此对应喜欢把模板文件使用".html"的格式,] /include/arc.archives. ...

  4. 深度clone和浅clone

    首先等你有空的时候可以看这篇,要用可以看我这篇 https://www.cnblogs.com/echolun/p/7889848.html 1.有一点需要明确的是 深拷贝只是针对引用数据类型来说的, ...

  5. ICEM-缺口圆柱

    原视频下载地址:https://pan.baidu.com/s/1bpahxd9 密码: bpp7

  6. 《恶魔人crybaby》豆瓣短评爬取

    作业要求来源:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE1/homework/3159 爬虫综合大作业 选择一个热点或者你感兴趣的主题. 选择爬取的对象 ...

  7. 解决vs2010按ctrl+f5,调试窗口一闪而过的方法

    vs2010调试按F5与按Ctrl+F5有什么区别 Ctrl F5测试运行后不自动推出控制台,直接按F5会自动退出去 解决vs2010按ctrl+f5,调试窗口一闪而过的方法 http://hi.ba ...

  8. 工具系列 | 使用Lodop进行WEB打印程序开发

    Lodop(标音:劳道谱,俗称:露肚皮)是专业WEB控件,用它既可裁剪输出页面内容,又可用程序代码直接实现 复杂打印.控件功能强大,却简单易用,所有调用如同JavaScript扩展语句. WEB套打可 ...

  9. ThinkPHP 控制器不存在问题排查

    新手经常会遇到这种问题,提示控制器找不到,一般的情况如下: 1. 命名空间地址错误 检查你的控制器命名空间是否正确

  10. 同时购入两台同款thinkpad笔记本电脑,分别使用同一账户激活office失败--------------解决方法(账户下有多个Office激活信息,重装后提示“许可证不正确或者最大激活次数”)

    如题所述,该问题曾多次与京东商城售后,京东thinkpad品牌售后,thinkpad售后等进行沟通,最后通过微软的电话激活才成功,不过在之后发现了这么一个帖子,应该是官方给出的,应该合理,没有实际验证 ...