Thông báo đẩy mysql

Như bạn có thể nhận thấy, gần đây tôi đã làm quen với chủ đề thông báo đẩy Tin nhắn qua đám mây của Firebase

Lần này tôi muốn chia sẻ với bạn ứng dụng phía máy chủ thông báo đẩy của tôi. Ứng dụng được tạo bằng khung Spring Boot

Ví dụ được cung cấp bao gồm hầu hết các trường hợp sử dụng gửi thông báo phổ biến, chẳng hạn như. gửi thông báo đẩy đến một chủ đề, trực tiếp đến thiết bị của người dùng hoặc gửi tin nhắn có tải trọng dữ liệu bổ sung

Bài đăng này không phải là hướng dẫn từng bước. Tôi sẽ tập trung vào những phần quan trọng nhất. Một ví dụ hoạt động đầy đủ có sẵn trên GitHub

Nếu bạn chưa có ứng dụng phía máy khách để nhận thông báo đẩy, bạn nên xem xét việc sử dụng ứng dụng Ionic mà tôi đã mô tả trước đó. Chúc vui vẻ

Đi nào

Hãy bắt đầu với việc tích hợp Firebase

Trước hết, bạn phải tạo khóa quản trị SDK Firebase của riêng mình. Về cơ bản, đó là một tệp JSON chứa thông tin đăng nhập dự án Firebase của bạn. Bạn sẽ cần nó để ủy quyền phía máy chủ (thông tin thêm)

Đăng nhập vào bảng điều khiển Firebase của bạn. Chuyển đến Cài đặt dự án -> Tài khoản dịch vụ rồi nhấp vào nút Tạo khóa riêng tư mới

 

Thông báo đẩy mysql

Tạo và lưu tệp. Chúng tôi sẽ sử dụng nó trong các bước tiếp theo

Ứng dụng khởi động mùa xuân

Đặt tệp JSON SDK quản trị Firebase đã tạo bên trong các tệp dự án Spring Boot của bạn (nếu không có, bạn có thể tạo tệp đó tại đây)

Trong trường hợp của tôi, tôi đã tạo thư mục google bên trong src/main/resources và sau đó sao chép tệp được tạo vào đó (thông báo đẩy- . json) .
Sau đó, trong ứng dụng của tôi. thuộc tính, tôi đã thêm một cặp khóa/giá trị mới chứa đường dẫn tệp.

app.firebase-configuration-file=google/push-notifications-example-firebase-adminsdk.json

Bây giờ, chúng tôi sẽ cần các phụ thuộc Firebase, vì vậy hãy thêm một số. Tôi đã sử dụng Maven làm người quản lý phụ thuộc

trong pom của tôi. phụ thuộc xml tôi đặt một phụ thuộc bổ sung

        <dependency>
            <groupId>com.google.firebase</groupId>
            <artifactId>firebase-admin</artifactId>
            <version>6.8.1</version>
        </dependency>

Bây giờ chúng ta phải khởi tạo ứng dụng Firebase của mình. Đây là thời gian để sử dụng ứng dụng của chúng tôi. tệp cấu hình firebase. Tôi đã sử dụng chú thích @Value để đưa giá trị đường dẫn vào trường Chuỗi

...

@Service
public class FCMInitializer {

    @Value("${app.firebase-configuration-file}")
    private String firebaseConfigPath;

    Logger logger = LoggerFactory.getLogger(FCMInitializer.class);

    @PostConstruct
    public void initialize() {
        try {
            FirebaseOptions options = new FirebaseOptions.Builder()
                    .setCredentials(GoogleCredentials.fromStream(new ClassPathResource(firebaseConfigPath).getInputStream())).build();
            if (FirebaseApp.getApps().isEmpty()) {
                FirebaseApp.initializeApp(options);
                logger.info("Firebase application has been initialized");
            }
        } catch (IOException e) {
            logger.error(e.getMessage());
        }
    }

}

Trình khởi tạo FCMI. java

Phương thức khởi tạo () đang được gọi khi khởi động ứng dụng nhờ chú thích @PostConstruct

Gửi thông báo đẩy

Bước tiếp theo là chuẩn bị lớp dịch vụ thông báo đẩy của chúng tôi.
Nhưng trước hết, tôi tách các trường hợp sử dụng sau.

  • gửi thông báo đẩy tới chủ đề bằng dữ liệu mẫu (được xác định trong ứng dụng. của cải)
  • gửi thông báo đẩy mẫu theo lịch trình đến chủ đề (mỗi phút)
  • gửi thông báo đẩy với tải trọng dữ liệu bổ sung (đối tượng dữ liệu khóa/giá trị do người dùng xác định, xem tài liệu để biết thêm thông tin)
  • gửi thông báo đẩy mà không cần tải dữ liệu bổ sung
  • gửi thông báo đẩy tới một người dùng cụ thể

Gửi thông báo đẩy mà không có ví dụ tải trọng dữ liệu từ lớp FCMService

@Service
public class FCMService {

    ...

    public void sendMessageWithoutData(PushNotificationRequest request)
            throws InterruptedException, ExecutionException {
        Message message = getPreconfiguredMessageWithoutData(request);
        String response = sendAndGetResponse(message);
        logger.info("Sent message without data. Topic: " + request.getTopic() + ", " + response);
    }

    ...

    private String sendAndGetResponse(Message message) throws InterruptedException, ExecutionException {
        return FirebaseMessaging.getInstance().sendAsync(message).get();
    }

    private AndroidConfig getAndroidConfig(String topic) {
        return AndroidConfig.builder()
                .setTtl(Duration.ofMinutes(2).toMillis()).setCollapseKey(topic)
                .setPriority(AndroidConfig.Priority.HIGH)
                .setNotification(AndroidNotification.builder().setSound(NotificationParameter.SOUND.getValue())
                        .setColor(NotificationParameter.COLOR.getValue()).setTag(topic).build()).build();
    }

    private ApnsConfig getApnsConfig(String topic) {
        return ApnsConfig.builder()
                .setAps(Aps.builder().setCategory(topic).setThreadId(topic).build()).build();
    }

    private Message getPreconfiguredMessageWithoutData(PushNotificationRequest request) {
        return getPreconfiguredMessageBuilder(request).setTopic(request.getTopic())
                .build();
    }

    ...

    private Message.Builder getPreconfiguredMessageBuilder(PushNotificationRequest request) {
        AndroidConfig androidConfig = getAndroidConfig(request.getTopic());
        ApnsConfig apnsConfig = getApnsConfig(request.getTopic());
        return Message.builder()
                .setApnsConfig(apnsConfig).setAndroidConfig(androidConfig).setNotification(
                        new Notification(request.getTitle(), request.getMessage()));
    }


}

Nếu bạn thực sự muốn kiểm tra nó, bạn có thể thử chạy ứng dụng ngay bây giờ và gọi các phương thức thích hợp

Trong trường hợp của tôi, để rõ ràng, tôi đã thêm một lớp khác – PushNotificationService sẽ được PushNotificationController sử dụng trực tiếp trong các bước tiếp theo

Hãy xem PushNotificationService

...

@Service
public class PushNotificationService {

    @Value("#{${app.notifications.defaults}}")
    private Map<String, String> defaults;

    private Logger logger = LoggerFactory.getLogger(PushNotificationService.class);
    private FCMService fcmService;

    public PushNotificationService(FCMService fcmService) {
        this.fcmService = fcmService;
    }

    @Scheduled(initialDelay = 60000, fixedDelay = 60000)
    public void sendSamplePushNotification() {
        try {
            fcmService.sendMessageWithoutData(getSamplePushNotificationRequest());
        } catch (InterruptedException | ExecutionException e) {
            logger.error(e.getMessage());
        }
    }

    public void sendPushNotification(PushNotificationRequest request) {
        try {
            fcmService.sendMessage(getSamplePayloadData(), request);
        } catch (InterruptedException | ExecutionException e) {
            logger.error(e.getMessage());
        }
    }

    public void sendPushNotificationWithoutData(PushNotificationRequest request) {
        try {
            fcmService.sendMessageWithoutData(request);
        } catch (InterruptedException | ExecutionException e) {
            logger.error(e.getMessage());
        }
    }


    public void sendPushNotificationToToken(PushNotificationRequest request) {
        try {
            fcmService.sendMessageToToken(request);
        } catch (InterruptedException | ExecutionException e) {
            logger.error(e.getMessage());
        }
    }


    private Map<String, String> getSamplePayloadData() {
        Map<String, String> pushData = new HashMap<>();
        pushData.put("messageId", defaults.get("payloadMessageId"));
        pushData.put("text", defaults.get("payloadData") + " " + LocalDateTime.now());
        return pushData;
    }


    private PushNotificationRequest getSamplePushNotificationRequest() {
        PushNotificationRequest request = new PushNotificationRequest(defaults.get("title"),
                defaults.get("message"),
                defaults.get("topic"));
        return request;
    }


}

Dịch vụ thông báo đẩy

Như bạn thấy, chúng ta lại có chú thích @Value ở đây.
Tại sao? .

Vì vậy, thay vì đưa một giá trị duy nhất từ ​​các thuộc tính vào một biến Chuỗi cụ thể, tôi quyết định sử dụng loại Bản đồ để đơn giản hóa. Nó vẫn sử dụng cùng một chú thích @Value

Một lần nữa, chúng tôi lưu trữ các giá trị mặc định trong ứng dụng. của cải. Vì vậy, ứng dụng. thông báo. khóa mặc định trông như thế này

app.notifications.defaults={topic: 'common', title: 'Common topic - Hello', message: 'Sending test message \uD83D\uDE42', token: 'ss22t03wz208eg:APA2idkkow223FE_0v5yHxqCLTyxAQafj6nWaqi4QzwZTW004q1PUux63UsFN', payloadMessageId: '123', payloadData: 'Hello. This is payload content.'}

ứng dụng. của cải

Hơn nữa, bạn có thể thấy chúng tôi đang sử dụng FCMService trực tiếp, chuyển các đối tượng yêu cầu thông báo tới nó

Để lên lịch, tôi đã sử dụng chú thích @Scheduled với độ trễ ban đầu là 1 phút. (tham số initDelay) và 1 phút. khoảng thời gian gửi (tham số fixedDelay). Hãy nhớ chú thích lớp Ứng dụng của bạn với @EnableScheduling

điểm cuối

Hãy tương tác với các dịch vụ của chúng tôi và xây dựng bộ điều khiển

Đối với mục đích trình bày, tôi đã hiển thị các phương thức dịch vụ của mình dưới dạng điểm cuối API REST để gửi tin nhắn trực tiếp, tùy chỉnh (đến chủ đề hoặc người đăng ký cụ thể) có/không có tải trọng dữ liệu hoặc kích hoạt gửi thông báo mặc định

...

@RestController
public class PushNotificationController {

    private PushNotificationService pushNotificationService;

    public PushNotificationController(PushNotificationService pushNotificationService) {
        this.pushNotificationService = pushNotificationService;
    }

    @PostMapping("/notification/topic")
    public ResponseEntity sendNotification(@RequestBody PushNotificationRequest request) {
        pushNotificationService.sendPushNotificationWithoutData(request);
        return new ResponseEntity<>(new PushNotificationResponse(HttpStatus.OK.value(), "Notification has been sent."), HttpStatus.OK);
    }

...

    @GetMapping("/notification")
    public ResponseEntity sendSampleNotification() {
        pushNotificationService.sendSamplePushNotification();
        return new ResponseEntity<>(new PushNotificationResponse(HttpStatus.OK.value(), "Notification has been sent."), HttpStatus.OK);
    }
}

PushNotificationController. đoạn java

Kiểm tra các điểm cuối REST bằng cURL

Hãy kiểm tra các điểm cuối của chúng tôi. Tôi đã sử dụng cURL cho tác vụ này nhưng bạn có thể sử dụng các công cụ yêu cầu HTTP yêu thích của mình hoặc viết một ứng dụng khách nhỏ cho việc này

  • GET /notification – Kích hoạt thông báo mẫu với các giá trị mặc định đang gửi

curl -H "Content-Type: application/json" -X GET http://localhost:8080/notification

  • POST /notification/topic – Gửi tin nhắn đến một chủ đề cụ thể

________số 8

  • POST /notification/token – Gửi tin nhắn đến một thiết bị cụ thể (có token)

curl -d '{"title":"Hey you!", "message":"Watch out!", "token":"cct00ebz8eg:APA91bFcTkFE_0Qafj6nWv5yHxqCLTyxAaqi4QzwsFNLP5M9G78X8Z5UMZTW004q1PUux63Ut-1WMGVToMNTdB3ZfO8lCZlc4lGpxm7LBdWfkhaUxdbpQ5xIO5cAb-w9H2dBLNHT7i-U", "topic": ""}' -H "Content-Type: application/json" -X POST http://localhost:8080/notification/token

  • POST /notification/data – Gửi tin nhắn đến một chủ đề cụ thể với dữ liệu tải trọng bổ sung.
    Xin lưu ý . trong trường hợp này tôi lấy mặc định từ ứng dụng. thuộc tính như tải trọng mẫu. Trong ứng dụng của mình, có lẽ bạn nên sử dụng dữ liệu API của bên thứ ba hoặc dữ liệu liên tục từ cơ sở dữ liệu của mình.

        <dependency>
            <groupId>com.google.firebase</groupId>
            <artifactId>firebase-admin</artifactId>
            <version>6.8.1</version>
        </dependency>
0

 

Nếu thành công, bạn sẽ nhận được phản hồi JSON sau với mã 200

        <dependency>
            <groupId>com.google.firebase</groupId>
            <artifactId>firebase-admin</artifactId>
            <version>6.8.1</version>
        </dependency>
1

Kết quả

Chà… Nếu được cấu hình đúng thì nó sẽ hoạt động. Tôi đã sử dụng ứng dụng Ionic và điện thoại Android với tư cách khách hàng

Hãy xem ảnh chụp màn hình này với các thông báo đã nhận

Thông báo đẩy mysql

Trong trường hợp này, ứng dụng phía máy khách không xử lý dữ liệu tải trọng bổ sung

Bạn có tò mò về màu vàng của thông báo không? .
Xem tài liệu tham khảo để biết thêm mô tả trường bổ sung.

Tóm lược

Trong bài đăng này, tôi đã đề cập đến việc tích hợp Firebase Cloud Messaging cơ bản với ứng dụng Spring Boot. Nếu bạn đang tìm cách triển khai thông báo đẩy phía máy chủ, tôi nghĩ đây là cách nên làm

Như tôi đã đề cập trước đây, ví dụ hoạt động đầy đủ có sẵn trên GitHub. Nếu bạn đang tìm kiếm một ứng dụng di động phía máy khách cơ bản, vui lòng xem bài đăng về ứng dụng thông báo đẩy Ionic trước đây của tôi

Xin lưu ý rằng ví dụ được cung cấp đã được thử nghiệm với một ứng dụng Android. Mặc dù tôi đã cung cấp một số cấu hình Dịch vụ thông báo đẩy (APNS) cơ bản của Apple nhưng bạn phải xử lý các sự cố tiềm ẩn khi phát triển ứng dụng iOS. Nếu bạn quản lý để làm điều đó xin vui lòng cho tôi biết