一、需求背景
1.背景介绍
上一章**Redis简介、使用**中,讲述了redis服务端的Windows版本安装,以及Java客户端Jedis的使用。
引入Redis提供的客户端依赖就可实现和Redis服务端实现数据传输
2.需求简介
在不引入依赖的情况下,自己通过Java代码实现和Redis服务端实现数据传输
二、需求分析
1.需求拆解
想和Redis服务端进行数据传输
a.首先需要连接服务器(传输层)
b.传输的数据以字节、接口协议的方式进行,那么就需要将用户输入的数据转化为需要的数据格式(数据处理层)
c.为了方便使用者完成以上动作,提供相应的实现方法(操作层)
2.难点解析
a.获取传输给服务器的数据格式
传输的数据以字节、接口协议的方式进行。那么是以何种方式进行呢?
我们可以利用Java创建一个伪服务器,然后通过Jedis提供的set方法向伪服务器放数据
public static void main(String[] args) throws IOException {
//创建本机端口6379的服务器
ServerSocket serverSocket = new ServerSocket(6379);
Socket socket = serverSocket.accept();
//获取写进服务器的数据
InputStream inputStream = socket.getInputStream();
byte b[] = new byte[1024];
inputStream.read(b);
System.out.println(new String(b));
}
启动上面的方法,开启伪服务器
import redis.clients.jedis.Jedis;
public class App {
public static void main(String[] args) {
//向本机建立的伪服务器放入数据
Jedis jedis = new Jedis("localhost",6379);
jedis.set("foo", "bar");
String value = jedis.get("foo");
System.out.println("取得值为:"+value);
}
}
执行上面的客户端方法,发送数据。查看伪服务器端控制台,结果如下:
由此看出,set(“foo”, “bar”)实际上传给服务端的数据如上样式。
b.解析数据协议
协议规则可查看Redis官网https://redis.io/topics/protocol
上面示例中传给服务器的第一行为:*3(根据官网描述,*在第一个字节则表示数组,*3表示数组个数为3。[$3,SET]、[$3,foo]、[$3,bar])
第二行:$3( $在第一个字节则表示字符,$3则表示有三个字节:S E T )
第三行:SET(就是执行set操作)
后面依次类推
而每一行在什么时候结尾(结尾标记)。由上面截图中最后一句英文可以看出"\r\n"代表一行结束。
三、搭建框架
1.流程图解
2.逻辑梳理
流程图如上所示:
1.用户创建操作层中Jedis对象,通过构造方法将IP、端口传入
2.Jedis的有参构造方法中创建传输层的Connection对象,将IP、端口数值放入connection对象中
3.用户调用操作层的Jedis类提供的set、get方法进行操作
4.操作层的Jedis类提供的set、get方法调用传输层中的sendCommand方法,方法中先调用Connection类中提供的connect方法,进行连接redis服务器
5.sendCommand方法再调用数据处理层类Protocol中sendCommand方法,处理数据
6.将处理好的数据,传输给redis
四、代码实现
/**
* 提供操作方法
*/
public class Jedis {
private Connection connection;
public Jedis(String ip, int port) {
connection = new Connection(ip, port);
}
public String set(final String key,final String value){
connection.sendCommand(Protocol.Command.SET,key.getBytes(),value.getBytes());
return "";
}
public String get(final String key){
return connection.sendCommand(Protocol.Command.GET,key.getBytes()).getReply();
}
}
/**
* 协议
*/
public class Protocol {
private static final String X = "*";
private static final String D = "$";
private static final String K = "\r\n";
/**
* 组装发送信息
* @param command
* @param outputStream
* @param b
*/
public static void sendCommand(Protocol.Command command,OutputStream outputStream,byte[] ...b){
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append(X).append(b.length+1).append(K);//*3
stringBuffer.append(D).append(command.name().length()).append(K);//$3
stringBuffer.append(command).append(K);
for(byte []bytes:b){
stringBuffer.append(D).append(bytes.length).append(K);
stringBuffer.append(new String(bytes)).append(K);
}
try {
System.out.println(stringBuffer.toString());
outputStream.write(stringBuffer.toString().getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
public static enum Command{
SET,GET
}
}
public class Connection {
private Socket socket;
private String ip;
private int port;
private OutputStream outputStream;
private InputStream inputStream;
public Connection(String ip, int port) {
this.ip = ip;
this.port = port;
}
public String getReply(){
byte b[] = new byte[1024];
try {
socket.getInputStream().read(b);
} catch (IOException e) {
e.printStackTrace();
}
return new String(b);
}
public Connection sendCommand(Protocol.Command command,byte[] ...b){
//连接
connect();
//发送
Protocol.sendCommand(command,outputStream,b);
return this;
}
private void connect() {
try {
socket = new Socket(ip, port);
outputStream = socket.getOutputStream();
inputStream = socket.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
}
}