предисловие
Несколько дней назад я изучал фреймворк Netty, написал несколько демок, а потом подумал, что смогу использовать его для написания чего-нибудь, а потом меня немного заинтересовало написание плагина идеи, поэтому я собирался написать плагин идеи.
Что писать, я вспомнил, что могу написать плагин для Redis для подключения к клиенту. Это также можно использовать с Netty. Хотя на рынке есть много клиентов Redis, таких как Redis Desktop Manager, многие из них платная.Вам нужно найти взломанную версию для проституции.Хотя функции, написанные самостоятельно, просты, но пользоваться ими удобнее и не нужно открывать отдельную программу.Много раз я просто хочу посмотреть, есть ли данные в redis сохраняется, так что этого достаточно.
Чтобы завершить этот плагин, вам необходимо иметь некоторые знания о Netty и java Gui. Если вы совсем не понимаете этого, вы можете сначала взглянуть на этот контент.
Создать проект
Вы можете видеть, что идея может напрямую выбрать создание подключаемого проекта.
Сгенерированная структура проекта
Внутри будет файл plugin.xml, который является важным файлом конфигурации для плагина.
Напишите код под src
Дизайн пользовательского интерфейса
Хотим написать боковое окно инструментов, тогда нам нужна верстка интерфейса, в идее используйте swingUi
В соответствии с выбором на картинке будет сгенерирован редактор пользовательского интерфейса.
Просто перетащите справа в среднее поле, чтобы завершить макет пользовательского интерфейса, и макет, который вы завершите, одновременно сгенерирует для вас соответствующий класс сущностей. Для какого компонента вы хотите сгенерировать поля в классе сущностей, укажите имя поля здесь в имени поля
Наконец, будет создан класс сущностей, как показано на следующем рисунке.
Затем вы можете написать бизнес-код в классе сущностей
основной код
Без лишних слов, давайте начнем с кода
public class RedisCliUi {
//这里都是生成的组件字段
private JButton connectButton;
private JTextField portText;
private JTextField commandText;
private JButton commandButton;
private JTextField ipText;
private JTextArea textArea;
private JLabel ipLabel;
private JLabel portLabel;
private JLabel commandLabel;
private JPanel redisPanel;
private JButton cleanButton;
private JButton closeButton;
private JScrollPane scrollPane;
static String line = "\r\n";
static ChannelHandlerContext Context;
//实体类构造
public RedisCliUi(Project project, ToolWindow toolWindow) {
// 连接按钮监听
connectButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (StringUtils.isNotBlank(ipText.getText()) && StringUtils.isNotBlank(portText.getText())) {
new Thread(() -> {
connect(ipText.getText().trim(), portText.getText().trim());
}).start();
}
}
});
// 命令按钮监听
commandButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Context.writeAndFlush(getRedisMessage(Context, commandText.getText()));
}
});
// 清空按钮监听
cleanButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
textArea.setText("");
}
});
// 关闭连接按钮监听
closeButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Context.close();
}
});
// 文本框回车事件监听
textArea.addKeyListener(new KeyAdapter() {
@Override
public void keyTyped(KeyEvent e) {
if ((char) e.getKeyChar() == KeyEvent.VK_ENTER) {
String text = textArea.getText();
System.out.println(text);
String[] split = text.split("\n");
String s = split[split.length - 1];
System.out.println(s);
Context.writeAndFlush(getRedisMessage(Context, s));
}
}
});
// 端口号输入框回车事件监听
portText.addKeyListener(new KeyAdapter() {
@Override
public void keyTyped(KeyEvent e) {
if ((char) e.getKeyChar() == KeyEvent.VK_ENTER) {
if (StringUtils.isNotBlank(ipText.getText()) && StringUtils.isNotBlank(portText.getText())) {
new Thread(() -> {
connect(ipText.getText().trim(), portText.getText().trim());
}).start();
}
}
}
});
}
// 整个ui最外层的panel提供get方法
public JPanel getRedisPanel() {
return redisPanel;
}
// 通过netty客户端连接Redis方法
// 这里是netty的客户端代码
public void connect(String ip, String port) {
NioEventLoopGroup group = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel channel) throws Exception {
ChannelPipeline pipeline = channel.pipeline();
// pipeline.addLast(new LoggingHandler(LogLevel.INFO));
pipeline.addLast(new RedisDecoder());
pipeline.addLast(new RedisBulkStringAggregator());
pipeline.addLast(new RedisArrayAggregator());
pipeline.addLast(new RedisEncoder());
pipeline.addLast(new ChannelInboundHandlerAdapter() {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("连接redis 成功");
textArea.append("连接redis 成功");
textArea.append(line);
Context = ctx;
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
RedisMessage redisMessage = (RedisMessage) msg;
// 打印响应消息
printAggregatedRedisResponse(redisMessage);
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
ctx.close();
textArea.append("连接已关闭");
textAreaFocus(textArea, line);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
textArea.append("连接出现异常已关闭");
textAreaFocus(textArea, line);
}
});
}
});
try {
ChannelFuture channelFuture = bootstrap.connect(ip, Integer.parseInt(port)).sync();
channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
textArea.append("Redis连接 失败,请输入正确的ip与端口号");
textAreaFocus(textArea, line);
} finally {
group.shutdownGracefully();
}
}
// 处理redis返回数据
private void printAggregatedRedisResponse(RedisMessage msg) {
if (msg instanceof SimpleStringRedisMessage) {
System.out.println(((SimpleStringRedisMessage) msg).content());
textArea.append(((SimpleStringRedisMessage) msg).content());
textAreaFocus(textArea, line);
} else if (msg instanceof ErrorRedisMessage) {
System.out.println(((ErrorRedisMessage) msg).content());
textArea.append(((ErrorRedisMessage) msg).content());
textAreaFocus(textArea, line);
} else if (msg instanceof IntegerRedisMessage) {
System.out.println(((IntegerRedisMessage) msg).value());
textArea.append(String.valueOf(((IntegerRedisMessage) msg).value()));
textAreaFocus(textArea, line);
} else if (msg instanceof FullBulkStringRedisMessage) {
System.out.println(getString((FullBulkStringRedisMessage) msg));
textArea.append(getString((FullBulkStringRedisMessage) msg));
textAreaFocus(textArea, line);
} else if (msg instanceof ArrayRedisMessage) {
for (RedisMessage child : ((ArrayRedisMessage) msg).children()) {
printAggregatedRedisResponse(child);
}
} else {
throw new CodecException("unknown message type: " + msg + "\r\n");
}
}
private static String getString(FullBulkStringRedisMessage msg) {
if (msg.isNull()) {
return "(null)";
}
return msg.content().toString(CharsetUtil.UTF_8);
}
// 处理文本框光标位置在最后一行
public void textAreaFocus(JTextArea textArea, String line) {
textArea.append(line);
textArea.selectAll();
textArea.setCaretPosition(textArea.getSelectedText().length());
textArea.requestFocus();
}
// 将字符串处理成redis可以读取的消息
public static RedisMessage getRedisMessage(ChannelHandlerContext ctx, String str) {
// 匹配字符中空格分隔
String[] commands = str.split("\s+");
List<RedisMessage> children = new ArrayList<>(commands.length);
for (String cmdString : commands) {
children.add(new FullBulkStringRedisMessage(ByteBufUtil.writeUtf8(ctx.alloc(), cmdString)));
}
return new ArrayRedisMessage(children);
}
}
Логика приведенного выше кода заключается в том, что класс сущности начинает создаваться и загружает в него прослушиватель событий, передает входной ip и номер порта через метод connect() и устанавливает соединение с Redis через netty.
Метод channelRead() считывает данные, возвращаемые Redis.
Отправьте сообщение в Redis, прослушивая кнопку, которая отправляет команду, и событие ввода текстового поля.
создать окно
Для генерации окна также необходимо реализовать метод createToolWindowContent интерфейса ToolWindowFactory.
public class RedisClientFactory implements ToolWindowFactory {
// 生成右侧工具窗口
@Override
public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow) {
RedisCliUi redisClientUi = new RedisCliUi(project,toolWindow);
// 获取内容工厂的实例
ContentFactory contentFactory = ContentFactory.SERVICE.getInstance();
// 获取 ToolWindow 显示的内容
Content content = contentFactory.createContent(redisClientUi.getRedisPanel(), "", false);
// 设置 ToolWindow 显示的内容
toolWindow.getContentManager().addContent(content);
}
}
redisPanel — самая внешняя панель пользовательского интерфейса. Дайте ему метод get и передайте его в мастерскую контента, и он загрузит весь контент в пользовательском интерфейсе.
Нам также нужно настроить plugin.xml, чтобы настроить наше окно в него.
<extensions defaultExtensionNs="com.intellij">
<!-- Add your extensions here -->
<toolWindow id="RedisClient" secondary="false" anchor="right" factoryClass="window.RedisClientFactory"/>
</extensions>
Пока идентификатор не повторяется, вы можете привязку указать правую сторону, то есть инструмент фиксирует factoryClass в правой боковой панели.Заполните путь пакета RedisClientFactory, и он найдет окно генерации
Нажмите buiud и нажмите на изображение выше, чтобы создать zip-пакет плагина, и вы можете установить плагин локально.
Эффект
Вы можете отправлять команды в текстовом поле команды Redis или отправлять команды непосредственно в текстовое поле. Основной эффект аналогичен использованию redis_cli в Linux.
На данный момент разработка этого плагина завершена, и многие места не идеальны, прошу меня простить.
Плагин выложен на сетевой диск, если интересно, можете использовать сами
Связь:disk.baidu.com/yes/1 не давайте GY XQ4, пожалуйста…Код извлечения: n9f6