kafka安装请参考官网即可,本案例中使用2.8.1版本
mysql只负责记录
pom依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 阿里的json解析依赖 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-joda</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-parameter-names</artifactId>
</dependency>
<!-- 下边这个springboot自动创建实例 -->
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
<version>2.8.1</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.22</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.14</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.41</version>
</dependency>
</dependencies>
application.yml文件
server:
port: 80
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/wy?&serverTimezone=GMT%2B8&characterEncoding=utf-8
username: root
password: 123456
jpa:
database: MYSQL
show-sql: true
hibernate:
ddl-auto: update
naming-strategy: org.hibernate.cfg.ImprovedNamingStrategy
properties:
hibernate:
dialect:org.hibernate.dialect.MySQL5Dialect
kafka:
#消息监听的主体(自己用户的id)
topicsUser: 32882
#Kafka服务器地址
bootstrap-servers: 127.0.0.1:9092
producer:
#设置数据value的序列化处理类
value-serializer: org.apache.kafka.common.serialization.StringSerializer
consumer:
#设置数据value的反序列化处理类
value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
AppKafka.java启动主文件
package cn.com.wy.kafka;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Import;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.scheduling.annotation.EnableScheduling;
import cn.com.wy.kafka.chatInterface.LoginInteface;
import cn.com.wy.kafka.chatInterface.MainInterface;
import cn.com.wy.kafka.utils.SpringUtil;
import cn.com.wy.kafka.utils.YamlUtils;
/**
* Hello world!
*
*/
@EnableScheduling
@SpringBootApplication
@Import({SpringUtil.class,YamlUtils.class})
public class AppKafka
{
public static void main( String[] args ) throws Exception
{
System.setProperty("java.awt.headless", "false");
SpringApplication.run(AppKafka.class, args);
new MainInterface("32882");
}
}
MainInterface.java主界面
package cn.com.wy.kafka.chatInterface;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTextPane;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.core.JdbcTemplate;
import cn.com.wy.kafka.service.producerService;
import cn.com.wy.kafka.utils.SpringUtil;
/**
* 聊天主界面
* @author wy
*
*/
public class MainInterface {
@Autowired
private JdbcTemplate jdbc = SpringUtil.getBean(JdbcTemplate.class);;
//登录人id
@Value("${spring.kafka.topicsUser}")
private String ownUserId;
//发送业务层
private producerService product=SpringUtil.getBean(producerService.class);
private JFrame f = new JFrame("聊天");
private static JTextPane jtp = new JTextPane();
JScrollPane jsp = new JScrollPane(jtp);
//面板
JPanel jp = new JPanel();
//文本框的长度
JTextField jtf = new JTextField(25);
//按钮
JButton jb = new JButton("发送");
public MainInterface(String receiveUserId) {
jtp.setEditable(false);
f.add(jsp);
jp.add(jtf);
jp.add(jb);
//注意:需要将滚动条域面板全部添加到窗体中
f.add(jsp, BorderLayout.CENTER);
f.add(jp, BorderLayout.SOUTH);//窗体的下面(南部)
//注意:需要设置 标题、大小、位置、关闭,是否可见
f.setTitle("聊天框 服务端");
f.setSize(400, 300);
f.setLocation(300, 300);
//窗体关闭,程序就退出
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
//按钮绑定事件
jb.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
sendEdit();
//发送数据
product.send(jtf.getText(), receiveUserId);
}
});
//文本绑定事件
jtf.addKeyListener(new KeyListener() {
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyReleased(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
//回车键
if (e.getKeyCode() == KeyEvent.VK_ENTER) {//判断是不是回车键
sendEdit();
//发送数据
product.send(jtf.getText(), receiveUserId);
}
}
});
}
public void sendEdit(){
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateTime = df.format(new Date());
String str = dateTime+" 我"+":"+"\n"+jtf.getText();
setDocs(str,Color.red,false,14);
}
//编辑文本信息
public static void edit(String message){
// jta.append("\n"+message);
setDocs(message,Color.BLUE,true,14);
}
public static void insert(String str, AttributeSet attrSet) {
Document doc = jtp.getDocument();
str = "\n " + str ;
try {
doc.insertString(doc.getLength(), str, attrSet);
}
catch (BadLocationException e) {
System.out.println( "BadLocationException: " + e);
}
}
//设置文本
public static void setDocs(String str,Color col,boolean bold,int fontSize) {
SimpleAttributeSet attrSet = new SimpleAttributeSet();
StyleConstants.setForeground(attrSet, col);
//颜色
if(bold==true){
StyleConstants.setBold(attrSet, true);
}//字体类型
StyleConstants.setFontSize(attrSet, fontSize);
StyleConstants.setAlignment(attrSet, StyleConstants.ALIGN_RIGHT);
StyleConstants.setRightIndent(attrSet, 2);
//字体大小
insert(str, attrSet);
}
}
producerService.java发送消息
package cn.com.wy.kafka.service;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import javax.transaction.Transactional;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import cn.com.wy.kafka.entity.RecordEntity;
import cn.com.wy.kafka.utils.YamlUtils;
import com.alibaba.fastjson.JSONObject;
/**
* 发送消息实现层
* @author Administrator
*
*/
@Service
public class producerService {
@Autowired
private JdbcTemplate jdbc;
@Autowired
private KafkaTemplate<String,String> kafkaTemplate;
@Value("${spring.kafka.topicsUser}")
private String ownUserId;
/**
* 记录保存
* @param record
*/
@Transactional
public void save(RecordEntity record,String dateTime){
String uuid = UUID.randomUUID().toString().replace("-", "");
record.setId(uuid);
jdbc.execute("insert into `info_record` (`id`, `send_user_id`, `receive_user_id`, `message`, `create_time`, `delete_flg`) values('"+uuid+"','"+record.getSendUserId()+"','"+record.getReceiveUserId()+"','"+record.getMessage()+"','"+dateTime+"','"+record.getDeleteFlg()+"');");
}
/**
* 发送
* @param message 内容
* @param userId 接收人id
*/
@Transactional
public void send(String message,String userId) {
try{
//需要根据用户id查询用户名称
String userName = "";
Map<String,String> map = new HashMap<String, String>();
map.put("senUserId", ownUserId);
map.put("message", message);
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateTime = df.format(new Date());
map.put("time", dateTime);
String json = JSONObject.toJSONString(map);
ProducerRecord<String, String> record = new ProducerRecord(userId, json);
kafkaTemplate.send(record);
//写入记录表,方便后期查询使用
RecordEntity record1 = new RecordEntity();
record1.setMessage(json);
record1.setReceiveUserId(userId);
record1.setSendUserId(ownUserId);
save(record1,dateTime);
}catch(Exception e){
}
}
}
consumerController.java监听接收消息
package cn.com.wy.kafka;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.kafka.config.KafkaListenerEndpointRegistry;
import org.springframework.kafka.listener.ConsumerSeekAware;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import cn.com.wy.kafka.chatInterface.MainInterface;
import cn.com.wy.kafka.utils.SpringUtil;
import cn.com.wy.kafka.utils.YamlUtils;
import com.alibaba.fastjson.JSONObject;
/**
* 接收监听层
* @author wy
*
*/
@Component
public class consumerController implements ConsumerSeekAware{
@Autowired
JdbcTemplate jdbc;
Logger log = LoggerFactory.getLogger(consumerController.class);
/**
* 消息监听接口
* @param record
*/
@KafkaListener(topics = "${spring.kafka.topicsUser}",groupId="wy")
public void listen(ConsumerRecord<?, ?> record) {
Optional<?> kafkaMessage = Optional.ofNullable(record.value());
if (kafkaMessage.isPresent()) {
String str1 = (String) kafkaMessage.get();
Map<String,String> message = JSONObject.parseObject(str1,Map.class);
//发送人id
String senUserId = message.get("senUserId");
//查询发送人名称
List<Map<String, Object>> queryForList = jdbc.queryForList("SELECT iu.user_name as name FROM info_user iu WHERE iu.id='"+senUserId+"'");
String str = message.get("message");
String time = message.get("time");
if(queryForList!=null && queryForList.size()>0){
String name = (String) queryForList.get(0).get("name");
if(!StringUtils.isEmpty(name)){
str=time+" "+name+":"+str;
}
}
MainInterface.edit("\n"+str);
}
}
}
下边是所需实体,如不需要数据库可以屏蔽掉,目前 数据库只作为记录,后期会调整为es
UserEntity.java
package cn.com.wy.kafka.entity;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
@Table(name = "info_user")
public class UserEntity {
/**
* 用户id
*/
@Id
@GeneratedValue(generator = "JDBC")
private String id;
/**
* 用户名
*/
@Column(name = "user_name")
private String userName;
/**
* 用户昵称
*/
@Column(name = "user_nickname")
private String userNickname;
/**
* 删除标识,0未删除,1已删除
*/
@Column(name = "delete_flg")
private int deleteFlg;
/**
* 在线状态,0未在线,1已在线
*/
@Column(name = "online_status")
private int onlineStatus;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserNickname() {
return userNickname;
}
public void setUserNickname(String userNickname) {
this.userNickname = userNickname;
}
public int getDeleteFlg() {
return deleteFlg;
}
public void setDeleteFlg(int deleteFlg) {
this.deleteFlg = deleteFlg;
}
public int getOnlineStatus() {
return onlineStatus;
}
public void setOnlineStatus(int onlineStatus) {
this.onlineStatus = onlineStatus;
}
}
RecordEntity.java
package cn.com.wy.kafka.entity;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
@Table(name = "info_record")
public class RecordEntity {
/**
* id
*/
@Id
@GeneratedValue(generator = "JDBC")
private String id;
/**
* 发送用户id
*/
@Column(name = "send_user_id")
private String sendUserId;
/**
* 接收用户id
*/
@Column(name = "receive_user_id")
private String receiveUserId;
/**
* 信息
*/
@Column(name = "message")
private String message;
/**
* 创建时间
*/
@Column(name = "create_time")
private Date createTime;
/**
* 删除标识,0未删除,1已删除
*/
@Column(name = "delete_flg")
private int deleteFlg;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getSendUserId() {
return sendUserId;
}
public void setSendUserId(String sendUserId) {
this.sendUserId = sendUserId;
}
public String getReceiveUserId() {
return receiveUserId;
}
public void setReceiveUserId(String receiveUserId) {
this.receiveUserId = receiveUserId;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public int getDeleteFlg() {
return deleteFlg;
}
public void setDeleteFlg(int deleteFlg) {
this.deleteFlg = deleteFlg;
}
}
数据库脚本
CREATE DATABASE /*!32312 IF NOT EXISTS*/`wy` /*!40100 DEFAULT CHARACTER SET utf8 */;
USE `wy`;
/*Table structure for table `info_record` */
CREATE TABLE `info_record` (
`id` varchar(32) NOT NULL COMMENT '主键',
`send_user_id` varchar(32) DEFAULT NULL COMMENT '发送用户id',
`receive_user_id` varchar(32) DEFAULT NULL COMMENT '接收用户id',
`message` text COMMENT '内容',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '时间',
`delete_flg` int(11) DEFAULT NULL COMMENT '撤回',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='聊天记录表';
/*Table structure for table `info_user` */
CREATE TABLE `info_user` (
`id` varchar(32) NOT NULL COMMENT '主键',
`user_name` varchar(64) DEFAULT NULL COMMENT '用户名称',
`user_nickname` varchar(64) DEFAULT NULL COMMENT '昵称',
`delete_flg` int(11) DEFAULT NULL COMMENT '删除标识',
`online_status` int(11) DEFAULT NULL COMMENT '在线状态',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户';