Java实例 基于UDP及自建知识库的聊天机器人 01 涉及技术栈 02 运行效果展示
代码已上传仓库,切换分支后拉取。 分支:Chatting
03 项目目录说明
04 程序工作流程说明
主要包含以下步骤:
Main()进入程序进行登录,输入用户名判断判断成功,进入聊天室,同时创建客户端服务端UDP通信进程客户端输入文字提问服务端收到信息,创建IO流,进行本地知识库的读取,并作出相应的回复Data()获取当前时间,设置Server和Client的聊天记录的展示
05 关键知识及代码
此处只展示关键代码,其余代码见Gitee仓库。
(1)文件读写流
包括文件的读写和字符串的处理,涉及到了String类的一些方法:
文件读写流相关知识:
集合相关知识:
package fileIO;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
/**
* @description: 文件的读写流使用字符缓冲流进行
* @author:StrivePeng
*/
public class FileIo {
public static final String FILEPATH = "src/fileIO/知识库.txt";
private static BufferedReader reader; // 字符缓冲流
private ArrayList<String> answerList = new ArrayList<String>(); // 存放答案
private ArrayList<String> questionList = new ArrayList<String>(); // 存放问题
/**
* @throws IOException io异常
* @throws IllegalArgumentException 文件不符合预期格式
* 构造函数,读取文件数据存放到静态变量
*/
public FileIo() throws IOException, IllegalArgumentException {
try {
reader = new BufferedReader(new FileReader(FILEPATH)); // 初始化字符缓冲器
findKnowledge(); // 处理文件 存放变量集合中
} finally {
if (reader != null) {
// 关闭资源
reader.close();
}
}
}
/**
* @throws IOException io异常
* @description: 将知识库中的问题和答案分类存放到响应的数组中
* @author:StrivePeng
*/
private void findKnowledge() throws IOException {
// 按照行读取
String line;
while ((line = reader.readLine()) != null) {
// 判断是问题or答案
if (line.startsWith("答案")) {
String answer = line.substring("答案".length()); // 截取后面得字符串
answerList.add(answer);
}
if (line.startsWith("问题")) {
String question = line.substring("问题".length());
questionList.add(question);
}
}
}
public ArrayList<String> getAnswerList() {
return answerList;
}
public ArrayList<String> getQuestionList() {
return questionList;
}
}
(2)UDP通信相关
涉及到的一些知识点:
// 客户端
package udp;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class Client {
private static final int PORT = 8888; // 固定的端口号
private DatagramSocket clientSocket; // 未初始化的客户端
// 构造函数 同时初始化客户端
public Client() throws Exception {
clientSocket = new DatagramSocket();
}
/**
* @param message 消息内容
* @description: 向服务器发送消息
* @author: strivePeng
*/
public void clientSendMsg(String message) {
try {
InetAddress serverAddress = InetAddress.getByName("127.0.0.1"); // 固定一个客户端IP为 本地
byte[] sendBuffer = message.getBytes();
// 创建并发送数据包
DatagramPacket sendPacket = new DatagramPacket(sendBuffer, sendBuffer.length, serverAddress, PORT);
clientSocket.send(sendPacket);
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 服务端
package udp;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class Server {
private static final int PORT = 8888; // 固定的端口号
private DatagramSocket server; // 一个未初始化的服务端
// 构造函数
public Server() throws Exception {
server = new DatagramSocket(PORT); // 初始化服务端
}
/**
* @return 返回一个收到的字符串
* @description: 服务器接收客户端发来的消息
* @author: strivePeng
*/
public String serverReceiveMsg() {
try {
byte[] receiveBuffer = new byte[1024];
// 创建并接收数据包 同时转为字符串返回
DatagramPacket receivePacket = new DatagramPacket(receiveBuffer, receiveBuffer.length);
server.receive(receivePacket);
return new String(receivePacket.getData(), 0, receivePacket.getLength());
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
(3)Swing组件的使用
窗口结合IDEA的GUI Form可视化拖动设计。基本的创建步骤如下图所示:
Swing组件 基本组件:
当学习 Java Swing 时,深入了解各个组件的特性、属性以及适用场景是非常重要的。以下是对几个常用 Swing 组件的详细介绍:
JFrame:顶级窗口容器 属性: 适用场景: JPanel:面板容器 属性: 适用场景: JButton:按钮 属性: 适用场景: JLabel:标签 属性: 适用场景: JTextField:文本框 属性: 适用场景: JTextArea:多行文本框
属性:
适用场景:
适用场景: (4)类对象的引用
除此之外,在登录成功后涉及到了弹窗的关闭,此时使用了类对象的引用的传入,方便销毁登录界面。具体实现如下。
// 构造函数 同时传入登录界面的引用方便在登录成功后关闭
public LoginSuccessfulDialog(LoginJF loginJF) {
this.loginJF = loginJF; // 传入一个窗口对象的引用
this.setTitle("提示");
this.setContentPane(contentPane);
this.setModal(true);
this.getRootPane().setDefaultButton(buttonOK);
// 判断用户是否存在
if(loginJF.userIsExit){
// 用户存在
this.successfulDialog.setText("登录成功!");
// 设置按钮功能为点击后跳转到聊天界面
this.buttonOK.addActionListener(actionEvent -> onOK());
}else{
// 用户不存在
this.successfulDialog.setText("登录失败,请重新登录!");
this.buttonOK.addActionListener(actionEvent -> onCancel());
}
......
}
(5)线程调用GUI窗口
public static void main(String[] args) {
/*
使用了 SwingUtilities.invokeLater() 方法来确保 Swing 组件的初始化和显示操作在事件分派线程(Event Dispatch Thread,EDT)上执行。
在 Swing 中,GUI 的相关操作应该在 EDT 上执行,以确保线程安全性。
*/
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
LoginJF loginJF = new LoginJF();
loginJF.setVisible(true);
}
});
}
(6)Lambda表达式的使用
Lambda 表达式是 Java 8 中引入的一个强大的特性,它提供了一种更简洁、更方便的方式来实现函数式编程。Lambda 表达式通常在简单的、只有一个抽象方法的接口中发挥作用,使代码更为紧凑。Lambda 表达式的主要用途是简化匿名内部类的语法,使代码更加紧凑和易读。下面详细讲解 Lambda 表达式的用法:
基本语法
Lambda 表达式的基本语法如下:
(parameters) -> expression
或者
(parameters) -> { statements; }
程序中的使用
// 按钮监听事件绑定
this.resetButton.addActionListener(actionEvent -> reset());
// 判断用户是否存在
if(loginJF.userIsExit){
// 用户存在
this.successfulDialog.setText("登录成功!");
// 设置按钮功能为点击后跳转到聊天界面
this.buttonOK.addActionListener(actionEvent -> onOK());
}else{
// 用户不存在
this.successfulDialog.setText("登录失败,请重新登录!");
this.buttonOK.addActionListener(actionEvent -> onCancel());
}
// 开启聊天界面
SwingUtilities.invokeLater(()->{
ChattingJF chattingJF = new ChattingJF();
chattingJF.setVisible(true);
});
(7)日期获取与处理
/**
* @return 当前日期的字符串
* @description 获取当前时间并格式化为字符串
* @author strivePeng
*/
private String getCurrentTime() {
// 格式化日期 SimpleDateFormat
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日HH:mm:ss");
// 获取当前日期
Date data = new Date(System.currentTimeMillis());
// 格式化日期时间转为字符串
String str = sdf.format(data);
return str;
}
(8)知识库中的答案的搜索与展示
涉及到了更多的String字符串的处理以及List集合的操作,详见代码注释:
/**
* @param question 提问的问题
* @return 服务器返回的答案
* @throws IOException 文件IO异常
* @description 从知识库中返回答案
* @author strivePeng
*/
private String findAnswer(String question){
try{
FileIo fileIo = new FileIo();
for (String q : fileIo.getQuestionList()) {
if (question.trim().equals(q.trim())) {
// 根据问题和答案的索引一一对应的关系返回答案
return fileIo.getAnswerList().get(fileIo.getQuestionList().indexOf(q));
}
}
}catch (Exception e){
e.printStackTrace();
}
return "抱歉!我还没有学习到这方面的知识哦!!!";
}
06 结语
聊天机器人相关知识详情都在源码注释中详细备注,本次练习旨在为自己一阶段的学习进行检验,在本次实例中使用到了java基础的语法,以及异常处理,一小部分的线程处理,以及Swing组件的使用和文件的读写流等,适合新手上手以及对网路UDP通信的理解。
前期的学习参考了以下博客:CSDN博客