使用 Spring Boot 和 Vue.js 实现实时通知系统

使用 Spring Boot 和 Vue.js 实现实时通知系统

在这篇文章中,我们将教你如何从零开始实现一个简单的实时通知系统,使用 Spring Boot 作为后端,Vue.js 作为前端,结合 WebSocket 和 STOMP 协议实现实时推送通知,并通过电子邮件将通知内容发送给所有用户。

系统需求

  • 后端(Spring Boot) 支持接收、存储和广播通知。
  • 支持将通知发送到指定的用户邮箱。
  • 使用 WebSocket 推送通知到前端。
  • 前端(Vue.js) 使用 WebSocket 接收后端推送的通知。
  • 显示通知内容。
  • 提供输入框让用户发送新通知。

创建 Spring Boot 项目

1.1 初始化 Spring Boot 项目

首先,我们需要创建一个 Spring Boot 项目。如果你不熟悉 Spring Boot,可以通过 Spring Initializr 快速创建一个项目:

选择 Spring Boot 版本(如 2.7.x)。

选择依赖:Spring Web, Spring WebSocket, Spring Boot DevTools, Spring Data JPA, MySQL Driver, Spring Mail 等。

点击 Generate,下载项目并解压。

将解压后的项目导入到你的开发工具(如 IntelliJ IDEA 或 Eclipse)。

1.2 配置数据库

在 application.yml 或 application.properties 文件中配置数据库连接信息:

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/test?serverTimezone=Asia/Shanghai
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
  mail:
    host: smtp.yeah.net
    port: 465
    username: your-email@yeah.net
    password: your-email-password
    from: your-email@yeah.net
  websocket:
    enabled: true

1.3 实现 WebSocket 配置

我们需要配置 WebSocket 来支持通知的实时推送。创建一个 WebSocketConfig 类:

import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        // 处理客户端订阅消息的前缀
        config.enableSimpleBroker("/topic");
        // 设置应用程序消息的前缀
        config.setApplicationDestinationPrefixes("/app");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/notifications").withSockJS();  // 设置 WebSocket 端点
    }
}

1.4 通知服务

在后端,我们创建一个服务类 NotificationService 来处理通知的存储、广播和邮件发送。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Service;

@Service
public class NotificationService {

    @Autowired
    private SimpMessagingTemplate messagingTemplate;  // 用于 WebSocket 广播

    @Autowired
    private EmailService emailService;  // 邮件服务

    // 广播通知
    public void broadcastNotification(Notification notification) {
        messagingTemplate.convertAndSend("/topic/notifications", notification);  // 将通知发送到所有订阅者
    }

    // 发送邮件给所有用户
    public void sendNotificationToAll(String message) {
        // 假设我们有一个获取所有用户邮箱的列表
        List<String> emails = getAllEmails();
        for (String email : emails) {
            emailService.sendSimpleMail(new String[]{email}, "新通知", message);
        }
    }

    // 获取所有用户邮箱的模拟方法
    private List<String> getAllEmails() {
        // 这里可以通过数据库查询获取邮箱
        return Arrays.asList("user1@example.com", "user2@example.com");
    }
}

1.5 邮件服务

EmailService 负责通过 SMTP 发送邮件:

import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;

@Service
public class EmailService {

    @Autowired
    private JavaMailSender javaMailSender;

    @Value("${spring.mail.from}")
    private String from;

    public void sendSimpleMail(String[] to, String subject, String content) {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom(from);
        message.setTo(to);
        message.setSubject(subject);
        message.setText(content);
        javaMailSender.send(message);
    }
}

1.6 控制器

NotificationController 负责处理前端请求,接收新通知,并通过 WebSocket 广播和邮件发送通知。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/notifications")
public class NotificationController {

    @Autowired
    private NotificationService notificationService;

    @PostMapping("/send")
    public ResponseEntity<?> sendNotification(@RequestBody NotificationRequestDto request) {
        try {
            // 保存通知
            notificationService.saveNotification(request.getEmailRequest().getContent());
            // 广播通知
            notificationService.broadcastNotification(request.getNotification());
            // 发送邮件通知
            notificationService.sendNotificationToAll(request.getEmailRequest().getContent());
            return ResponseEntity.ok("通知已发送");
        } catch (Exception e) {
            return ResponseEntity.status(500).body("发送失败");
        }
    }
}

2. 创建 Vue.js 前端

2.1 创建 Vue 项目

我们通过 Vue CLI 创建一个新的 Vue 2 项目。你可以参考以下命令:

npm install -g @vue/cli
vue create notification-demo
cd notification-demo
npm run serve

2.2 安装 WebSocket 依赖

在 Vue 项目中,我们需要使用 sockjs-client 和 stomp.js 库来连接 WebSocket。你可以通过 npm 安装这些依赖:

npm install sockjs-client stompjs

2.3 Vue 实现通知

在 Vue 中,我们使用 WebSocket 接收后端推送的通知,并将其显示在页面上。以下是一个简单的 Vue 组件:

<template>
  <div id="app">
    <h1>通知系统</h1>
    <ul>
      <li v-for="notification in notifications" :key="notification.id">{{ notification.message }}</li>
    </ul>
    <form @submit.prevent="sendNotification">
      <textarea v-model="newNotification.message" placeholder="输入通知" required></textarea>
      <button type="submit">发送通知</button>
    </form>
    <audio ref="notificationSound" src="https://your-sound-file-url.com" preload="auto"></audio>
  </div>
</template>
<script>
import SockJS from 'sockjs-client';
import Stomp from 'stompjs';

export default {
  data() {
    return {
      notifications: [],
      newNotification: { message: '' },
      stompClient: null
    };
  },
  mounted() {
    this.setupWebSocket();
  },
  methods: {
    setupWebSocket() {
      const socket = new SockJS('http://localhost:8080/notifications');
      this.stompClient = Stomp.over(socket);
      this.stompClient.connect({}, (frame) => {
        this.stompClient.subscribe('/topic/notifications', (messageOutput) => {
          const notification = JSON.parse(messageOutput.body);
          this.notifications.push(notification);
          this.playNotificationSound();
        });
      });
    },
    sendNotification() {
      const request = {
        notification: this.newNotification,
        emailRequest: { content: this.newNotification.message }
      };
      fetch('/api/notifications/send', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(request)
      });
    },
    playNotificationSound() {
      this.$refs.notificationSound.play();
    }
  }
};
</script>

2.4 HTML 页面

前端页面显示接收到的通知,并允许用户发送新的通知。用户提交通知后,通知会通过 WebSocket 推送到其他客户端,同时通过邮件发送给所有用户。

<div id="app">
  <h1>通知Demo</h1>
  <ul>
    <li v-for="notification in notifications" :key="notification.id">{{ notification.message }}</li>
  </ul>
  <div>
    <h2>发送通知</h2>
    <form @submit.prevent="sendNotification">
      <textarea v-model="newNotification.message" placeholder="输入通知" required></textarea>
      <button type="submit">发送通知</button>
    </form>
  </div>
  <audio ref="notificationSound" src="your-notification-sound.mp3" preload="auto"></audio>
</div>

后面是加入将通知存入数据库的步骤。我们将使用 MySQL 数据库来存储通知信息,包括通知的内容和创建时间

3. 创建数据库表

在 MySQL 中创建一个表来存储通知。你可以使用以下 SQL 语句来创建表:

CREATE TABLE notifications (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    message VARCHAR(255) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
  • id:通知的唯一标识符。
  • message:通知的内容。
  • created_at:通知的创建时间。

4. 实现通知存储功能

我们需要在 NotificationService 中实现将通知保存到数据库的功能。通过使用 MyBatis 或 JPA(根据项目的配置),你可以将通知信息存储到数据库。

4.1 使用 MyBatis 存储通知

首先,我们创建一个 NotificationMapper 来与数据库交互:

4.1.1 创建 NotificationMapper 接口
import com.test.message.model.Notification;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface NotificationMapper {

    @Select("SELECT * FROM notifications WHERE id = #{id}")
    Notification findById(Long id);

    @Insert("INSERT INTO notifications (message, created_at) VALUES (#{message}, #{createdAt})")
    void save(Notification notification);
}
4.1.2 修改 NotificationService 以调用 Mapper 保存通知

NotificationService 中,我们调用 NotificationMappersave 方法将通知信息存入数据库:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Service;
import com.test.message.mapper.NotificationMapper;
import com.test.message.model.Notification;
import java.time.LocalDateTime;

@Service
public class NotificationService {

    @Autowired
    private SimpMessagingTemplate messagingTemplate;

    @Autowired
    private NotificationMapper notificationMapper;  // 注入 NotificationMapper

    @Autowired
    private EmailService emailService;

    // 保存通知到数据库
    public void saveNotification(String message) {
        Notification notification = new Notification();
        notification.setMessage(message);
        notification.setCreatedAt(LocalDateTime.now());
        notificationMapper.save(notification);  // 保存到数据库
    }

    // 广播通知
    public void broadcastNotification(Notification notification) {
        messagingTemplate.convertAndSend("/topic/notifications", notification);
    }

    // 发送通知给所有用户
    public void sendNotificationToAll(String message) {
        List<String> emails = getAllEmails();
        for (String email : emails) {
            emailService.sendSimpleMail(new String[]{email}, "新通知", message);
        }
    }

    // 获取所有用户邮箱的模拟方法
    private List<String> getAllEmails() {
        return Arrays.asList("user1@example.com", "user2@example.com");
    }
}
  • saveNotification 方法将通知的内容存储到数据库中,并且设置当前的创建时间。

4.2 更新控制器以调用保存通知的方法

我们需要更新 NotificationController,使其能够调用 NotificationServicesaveNotification 方法,并保存发送的通知。

4.2.1 修改 NotificationController
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/notifications")
public class NotificationController {

    @Autowired
    private NotificationService notificationService;

    // 获取所有通知
    @GetMapping
    public List<Notification> getNotifications() {
        return notificationService.getAllNotifications();
    }

    // 发送通知
    @PostMapping("/send")
    public ResponseEntity<?> sendNotification(@RequestBody NotificationRequestDto request) {
        try {
            // 保存通知到数据库
            notificationService.saveNotification(request.getEmailRequest().getContent());

            // 广播通知
            notificationService.broadcastNotification(request.getNotification());

            // 发送邮件通知给所有用户
            notificationService.sendNotificationToAll(request.getEmailRequest().getContent());

            return ResponseEntity.ok("通知已发送");
        } catch (Exception e) {
            return ResponseEntity.status(500).body("发送失败");
        }
    }
}
  • sendNotification 方法会将通知内容保存到数据库,并将通知广播到所有客户端,同时通过邮件发送通知。

5. 完善前端 Vue.js 部分

现在,后端已经能够将通知保存到数据库并广播。接下来,我们来完善前端部分,让它能够接收后端发送的通知,并展示这些通知。

5.1 安装 WebSocket 依赖

如前所述,我们需要安装 WebSocket 客户端依赖:

npm install sockjs-client stompjs

5.2 Vue.js 前端实现

在 Vue.js 中,我们创建一个 WebSocket 客户端来接收通知,并将其显示在页面上。

5.2.1 修改 App.vue 组件
<template>
  <div id="app">
    <h1>通知系统</h1>
    <ul>
      <li v-for="notification in notifications" :key="notification.id">{{ notification.message }}</li>
    </ul>
    <form @submit.prevent="sendNotification">
      <textarea v-model="newNotification.message" placeholder="输入通知" required></textarea>
      <button type="submit">发送通知</button>
    </form>
    <audio ref="notificationSound" src="your-notification-sound.mp3" preload="auto"></audio>
  </div>
</template>

<script>
import SockJS from 'sockjs-client';
import Stomp from 'stompjs';

export default {
  data() {
    return {
      notifications: [],
      newNotification: { message: '' },
      stompClient: null
    };
  },
  mounted() {
    this.setupWebSocket();
  },
  methods: {
    setupWebSocket() {
      const socket = new SockJS('http://localhost:8080/notifications');
      this.stompClient = Stomp.over(socket);
      this.stompClient.connect({}, (frame) => {
        this.stompClient.subscribe('/topic/notifications', (messageOutput) => {
          const notification = JSON.parse(messageOutput.body);
          this.notifications.push(notification);
          this.playNotificationSound();
        });
      });
    },
    sendNotification() {
      const request = {
        notification: this.newNotification,
        emailRequest: { content: this.newNotification.message }
      };
      fetch('/api/notifications/send', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(request)
      });
    },
    playNotificationSound() {
      this.$refs.notificationSound.play();
    }
  }
};
</script>
  • setupWebSocket 方法连接到 WebSocket 端点,并订阅 /topic/notifications 路径。
  • sendNotification 方法将通知发送到后端,并触发广播。

6. 总结

通过本文的扩展,你已经成功实现了一个包含 数据库存储WebSocket 实时通知推送的系统。系统功能如下:

  1. 存储通知:通知信息会被保存到 MySQL 数据库中。
  2. 实时广播:通知通过 WebSocket 推送到前端客户端。
  3. 邮件通知:通知内容会通过邮件发送到所有用户。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值