本文目录导读:

我将为您提供一个完整的Java直播系统案例,包括核心功能模块和代码实现。
系统架构
直播系统
├── 用户模块(登录、注册、个人信息)
├── 直播模块(开播、观看、互动)
├── 礼物系统
├── 聊天系统
├── 支付系统
└── 管理后台
核心技术栈
- 后端:Spring Boot + MyBatis Plus
- 实时通信:Netty + WebSocket
- 数据库:MySQL + Redis
- 视频处理:FFmpeg + HLS
- 前端:Vue.js + Element UI
核心代码实现
项目结构
com.live.broadcast/
├── controller/
│ ├── UserController.java
│ ├── LiveController.java
│ └── GiftController.java
├── service/
│ ├── UserService.java
│ ├── LiveService.java
│ └── MessageService.java
├── netty/
│ ├── NettyServer.java
│ └── WebSocketHandler.java
├── entity/
│ ├── User.java
│ ├── LiveRoom.java
│ └── GiftRecord.java
└── config/
└── MybatisPlusConfig.java
用户模块
@RestController
@RequestMapping("/api/user")
public class UserController {
@Autowired
private UserService userService;
@PostMapping("/login")
public Result login(@RequestBody LoginRequest request) {
String token = userService.login(request);
return Result.success(token);
}
@PostMapping("/register")
public Result register(@RequestBody User user) {
userService.register(user);
return Result.success();
}
@GetMapping("/info/{userId}")
public Result getUserInfo(@PathVariable Long userId) {
User user = userService.getUserInfo(userId);
return Result.success(user);
}
}
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Override
public String login(LoginRequest request) {
// 验证用户信息
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("username", request.getUsername());
wrapper.eq("password", MD5Util.encrypt(request.getPassword()));
User user = userMapper.selectOne(wrapper);
if (user == null) {
throw new BusinessException("用户名或密码错误");
}
// 生成token并存储到Redis
String token = UUID.randomUUID().toString().replace("-", "");
redisTemplate.opsForValue().set("token:" + token, user.getId(), 24, TimeUnit.HOURS);
return token;
}
@Override
public void updateUserStatus(Long userId, boolean online) {
// 更新用户在线状态
User user = userMapper.selectById(userId);
user.setOnline(online);
userMapper.updateById(user);
}
}
直播模块
@RestController
@RequestMapping("/api/live")
public class LiveController {
@Autowired
private LiveService liveService;
@PostMapping("/start")
public Result startLive(@RequestBody StartLiveRequest request) {
LiveRoom room = liveService.startLive(request);
return Result.success(room);
}
@PostMapping("/stop/{roomId}")
public Result stopLive(@PathVariable Long roomId) {
liveService.stopLive(roomId);
return Result.success();
}
@GetMapping("/info/{roomId}")
public Result getLiveInfo(@PathVariable Long roomId) {
LiveRoom room = liveService.getLiveInfo(roomId);
return Result.success(room);
}
@GetMapping("/hot")
public Result getHotLives() {
List<LiveRoom> rooms = liveService.getHotLives();
return Result.success(rooms);
}
}
@Service
public class LiveServiceImpl implements LiveService {
@Autowired
private LiveRoomMapper liveRoomMapper;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Override
@Transactional
public LiveRoom startLive(StartLiveRequest request) {
// 生成推流地址
String pushUrl = generatePushUrl(request.getUserId());
// 创建直播房间
LiveRoom room = new LiveRoom();
room.setAnchorId(request.getUserId());
room.setTitle(request.getTitle());
room.setCoverUrl(request.getCoverUrl());
room.setPushUrl(pushUrl);
room.setStreamKey(UUID.randomUUID().toString().replace("-", ""));
room.setStatus(1); // 1-直播中
room.setCreateTime(LocalDateTime.now());
liveRoomMapper.insert(room);
// 缓存到Redis
String roomKey = "live_room:" + room.getId();
redisTemplate.opsForValue().set(roomKey, room, 4, TimeUnit.HOURS);
// 异步启动FFmpeg推流
startFFmpegProcess(room);
return room;
}
@Override
public void stopLive(Long roomId) {
LiveRoom room = liveRoomMapper.selectById(roomId);
room.setStatus(0);
room.setEndTime(LocalDateTime.now());
liveRoomMapper.updateById(room);
// 清除Redis缓存
redisTemplate.delete("live_room:" + roomId);
// 停止FFmpeg进程
stopFFmpegProcess(roomId);
}
private String generatePushUrl(Long userId) {
String rtmpHost = "rtmp://live.example.com/live/";
return rtmpHost + userId + "_" + System.currentTimeMillis();
}
}
实时通信(Netty + WebSocket)
@Component
public class WebSocketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
private static final ConcurrentHashMap<Long, Channel> USER_CHANNELS = new ConcurrentHashMap<>();
@Autowired
private MessageService messageService;
@Override
protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame frame) {
String message = frame.text();
JSONObject jsonObject = JSON.parseObject(message);
switch (jsonObject.getInteger("type")) {
case 1: // 聊天消息
handleChatMessage(ctx, jsonObject);
break;
case 2: // 礼物消息
handleGiftMessage(ctx, jsonObject);
break;
case 3: // 进入直播间
handleEnterRoom(ctx, jsonObject);
break;
case 4: // 退出直播间
handleExitRoom(ctx, jsonObject);
break;
}
}
private void handleChatMessage(ChannelHandlerContext ctx, JSONObject message) {
Long roomId = message.getLong("roomId");
Long userId = message.getLong("userId");
String content = message.getString("content");
// 存储消息到Redis
ChatMessage chatMessage = new ChatMessage();
chatMessage.setRoomId(roomId);
chatMessage.setUserId(userId);
chatMessage.setContent(content);
chatMessage.setTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")));
// 广播给直播间所有用户
broadcastToRoom(roomId, JSON.toJSONString(chatMessage));
}
private void handleGiftMessage(ChannelHandlerContext ctx, JSONObject message) {
Long roomId = message.getLong("roomId");
Long userId = message.getLong("userId");
String giftId = message.getString("giftId");
// 验证用户余额和礼物信息
boolean success = messageService.sendGift(roomId, userId, giftId);
if (success) {
GiftMessage giftMessage = new GiftMessage();
giftMessage.setType("gift");
giftMessage.setUserId(userId);
giftMessage.setGiftId(giftId);
giftMessage.setContent("赠送了礼物");
// 广播礼物消息
broadcastToRoom(roomId, JSON.toJSONString(giftMessage));
}
}
private void broadcastToRoom(Long roomId, String message) {
for (Map.Entry<Long, Channel> entry : USER_CHANNELS.entrySet()) {
// 这里需要维护roomId与Channel的映射关系
if (entry.getValue().isActive()) {
entry.getValue().writeAndFlush(new TextWebSocketFrame(message));
}
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
ctx.close();
}
}
礼物系统
@Service
public class GiftServiceImpl implements GiftService {
@Autowired
private GiftMapper giftMapper;
@Autowired
private UserService userService;
@Override
@Transactional
public boolean sendGift(Long roomId, Long userId, String giftId) {
// 获取礼物信息
Gift gift = giftMapper.selectById(giftId);
if (gift == null) {
return false;
}
// 扣减用户余额
User user = userService.getUserById(userId);
if (user.getBalance() < gift.getPrice()) {
throw new BusinessException("余额不足");
}
// 记录礼物消费记录
GiftRecord record = new GiftRecord();
record.setUserId(userId);
record.setRoomId(roomId);
record.setGiftId(giftId);
record.setPrice(gift.getPrice());
record.setTime(LocalDateTime.now());
// 保存记录并扣款
giftRecordMapper.insert(record);
user.setBalance(user.getBalance() - gift.getPrice());
userService.updateUser(user);
// 更新主播收入
LiveRoom room = liveRoomMapper.selectById(roomId);
if (room != null) {
User anchor = userService.getUserById(room.getAnchorId());
anchor.setIncome(anchor.getIncome() + gift.getPrice() * 0.7);
userService.updateUser(anchor);
}
return true;
}
}
@Entity
@Table(name = "gift")
public class Gift {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private BigDecimal price;
private String iconUrl;
private boolean isVip;
// getter/setter...
}
配置类
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
@Bean
public NettyServer nettyServer() {
return new NettyServer(8088);
}
}
@Component
public class NettyServer {
private final int port;
private final ServerBootstrap bootstrap;
public NettyServer(int port) {
this.port = port;
this.bootstrap = new ServerBootstrap();
}
@PostConstruct
public void start() throws InterruptedException {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
bootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) {
ch.pipeline()
.addLast(new HttpServerCodec())
.addLast(new HttpObjectAggregator(65536))
.addLast(new WebSocketServerProtocolHandler("/ws"))
.addLast(new WebSocketHandler());
}
});
bootstrap.bind(port).sync();
log.info("Netty server started on port: {}", port);
}
}
数据库设计
-- 用户表
CREATE TABLE `user` (
`id` bigint NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL,
`password` varchar(100) NOT NULL,
`nickname` varchar(50) DEFAULT NULL,
`avatar` varchar(200) DEFAULT NULL,
`balance` decimal(10,2) DEFAULT '0.00',
`income` decimal(10,2) DEFAULT '0.00',
`level` int DEFAULT '1',
`online` tinyint(1) DEFAULT '0',
PRIMARY KEY (`id`)
);
-- 直播间表
CREATE TABLE `live_room` (
`id` bigint NOT NULL AUTO_INCREMENT,
`anchor_id` bigint NOT NULL, varchar(100) NOT NULL,
`cover_url` varchar(200) DEFAULT NULL,
`status` tinyint DEFAULT '0',
`push_url` varchar(200) DEFAULT NULL,
`stream_key` varchar(100) DEFAULT NULL,
`viewer_count` int DEFAULT '0',
`create_time` datetime DEFAULT NULL,
`end_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
);
-- 礼物表
CREATE TABLE `gift` (
`id` varchar(50) NOT NULL,
`name` varchar(50) NOT NULL,
`price` decimal(10,2) NOT NULL DEFAULT '0.00',
`icon_url` varchar(200) DEFAULT NULL,
`is_vip` tinyint(1) DEFAULT '0',
PRIMARY KEY (`id`)
);
-- 礼物记录表
CREATE TABLE `gift_record` (
`id` bigint NOT NULL AUTO_INCREMENT,
`user_id` bigint NOT NULL,
`room_id` bigint NOT NULL,
`gift_id` varchar(50) NOT NULL,
`price` decimal(10,2) NOT NULL,
`time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
);
-- 聊天记录表
CREATE TABLE `chat_record` (
`id` bigint NOT NULL AUTO_INCREMENT,
`room_id` bigint NOT NULL,
`user_id` bigint NOT NULL,
`content` varchar(500) DEFAULT NULL,
`time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
);
使用说明
启动系统
# 安装依赖 mvn clean install # 启动应用 java -jar live-broadcast.jar
配置环境
- 修改
application.yml中的数据库连接 - 配置Redis连接地址
- 设置FFmpeg路径
系统优化建议
- 高并发处理:使用消息队列(RabbitMQ/Kafka)处理聊天和礼物消息
- CDN加速:集成CDN分发视频流
- 缓存优化:使用Redis缓存热点数据
- 监控告警:集成Prometheus监控系统状态
这个案例涵盖了直播系统的主要功能模块,您可以根据实际需求进行扩展和优化。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播