如何使用Spring Boot发送通知(FCM)

5
我有一个API,并且当我更改名为“Meeting”的表中的内容时,我希望向智能手机发送通知。 为此,我正在创建一种类型为POST的方法,其中我发送以下JSON Body,同时还发送授权密钥(由Firebase提供)以及发送至以下URLhttps://fcm.googleapis.com/fcm/send
@Headers -> *******



 {
       "to": "/topics/groupNameChoosenByYou",
       "data": {
          "title": "Your title",
          "message": "Your message"
       }
    }

这是我的Android推送通知服务。
@Service
public class AndroidPushNotificationsService {

    private static final String FIREBASE_SERVER_KEY = "AAAAq88vWWE:APA91bF5rSyqGbx26AY5jm6NsEfwJynQsnTd1MPFOTOz1ekTGZyof3Vz6gBb0769MLLxD7EXMcqKiPIHnqLh5buHEeUASnpsn-ltxR1J8z3kWJIAPNWlPZB0r0zKkXMyWkrbT3BLPWmCdi-NZnP3Jkb2z-QqtwJt5Q";
    private static final String FIREBASE_API_URL = "https://fcm.googleapis.com/fcm/send";

    @Async
    public CompletableFuture<String> send(HttpEntity<String> entity) {

        RestTemplate restTemplate = new RestTemplate();

        ArrayList<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
        interceptors.add(new HeaderRequestInterceptor("Authorization", "key=" + FIREBASE_SERVER_KEY));
        interceptors.add(new HeaderRequestInterceptor("Content-Type", "application/json"));
        restTemplate.setInterceptors(interceptors);

        String firebaseResponse = restTemplate.postForObject(FIREBASE_API_URL, entity, String.class);

        return CompletableFuture.completedFuture(firebaseResponse);
    }
}

这是我的HeaderRequestInterceptor。
public class HeaderRequestInterceptor implements ClientHttpRequestInterceptor {

    private final String headerName;
    private final String headerValue;

    public HeaderRequestInterceptor(String headerName, String headerValue) {
        this.headerName = headerName;
        this.headerValue = headerValue;
    }

    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
            throws IOException {
        HttpRequest wrapper = new HttpRequestWrapper(request);
        wrapper.getHeaders().set(headerName, headerValue);
        return execution.execute(wrapper, body);
    }
}

这是我的控制器

@RestController
public class WebController {

    private final String TOPIC = "test";

    @Autowired
    AndroidPushNotificationsService androidPushNotificationsService;

    @RequestMapping(value = "/send", method = RequestMethod.GET, produces = "application/json")
    public ResponseEntity<String> send() throws JSONException {

        JSONObject body = new JSONObject();
        body.put("to", "/topics/" + TOPIC);
        body.put("priority", "high");

        JSONObject notification = new JSONObject();
        notification.put("title", "JSA Notification");
        notification.put("body", "Happy Message!");

        JSONObject data = new JSONObject();
        data.put("Key-1", "JSA Data 1");
        data.put("Key-2", "JSA Data 2");

        body.put("notification", notification);
        body.put("data", data);

        HttpEntity<String> request = new HttpEntity<>(body.toString());

        CompletableFuture<String> pushNotification = androidPushNotificationsService.send(request);
        CompletableFuture.allOf(pushNotification).join();

        try {
            String firebaseResponse = pushNotification.get();

            return new ResponseEntity<>(firebaseResponse, HttpStatus.OK);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        return new ResponseEntity<>("Push Notification ERROR!", HttpStatus.BAD_REQUEST);
    }
}

问题在于当我访问http://localhost:8080/springbootapi/send时,出现了404错误,但是服务器正在运行。我想知道我的代码是否有问题,因为FCM API需要使用POST方法,在我的/send 方法中我正在使用GET方法,所以基本上我正在创建一个API来调用其他API,以便在表格发生更改时向用户提供通知,这是主要目的。是否有更好的方法来实现这一点或者这种做法甚至是一个好的实践方式?

请确保您输入的URL正确。404通常是页面未找到错误/路径错误,由于您只进行了rest操作,因此必须是路径问题。确保在“端口”和“@RequestMapping”(在本例中为“/send”)之间没有任何路径前缀。 - Alexandru Hodis
上下文路径为空。该项目是一个JAR文件,但我将其放置为WAR文件,这会有问题吗? - José Nobre
3个回答

1

FCM需要POST,而您正在使用restTemplate发送POST。无论您的控制器是GET甚至DELETE都没有关系。 但当然,由于您正在发送某些内容而不是检索某些内容,因此应该将其设置为POST。 404意味着您输入了错误的URL。它应该是: http://localhost:8080/send(如果您正在使用8080端口)


我重复了这个过程并按照你说的尝试了,但它仍然不起作用,404还在:/ - José Nobre
你从你的控制器或 Firebase 得到了 404 吗? - Moler
我的控制器出现了404错误。上下文路径为空。这个项目本来是一个jar包,但我把它放成了war包,这会有问题吗? - José Nobre
不,战争不是问题。 检查一下你的Java类。也许你有一些配置类在改变你的基本URL。寻找那个Bean: @Bean public WebMvcRegistrationsAdapter webMvcRegistrationsHandlerMapping()或者通过实现EmbeddedServletContainerCustomizer 并且改变Override public void customize(ConfigurableEmbeddedServletContainer container)或者在属性中 server.contextPath=/??? - Moler

1
@RestController注解下方添加@RequestMapping("/springbootapi")或任何您想要的路径。

0

请确保您没有为Spring Boot应用程序设置任何上下文路径(检查日志并搜索Application.yml/properties中可能定义的上下文路径)

如果您收到404错误,则端口8080非常正常,但请确保仅由您的Spring Boot应用程序打开了该端口(还要检查控制台中Spring Boot打印的日志以获取端口信息)

我认为您的问题是,404错误不是因为FCM而是由于您在计算机上运行的应用程序引起的。


上下文路径为空。该项目是一个JAR文件,但我将其放置为WAR文件,这会有问题吗? - José Nobre
你能在日志中看到类似这样的内容吗?Mapped "{[/send],methods=[GET],produces=[application/json]}",...... 如果不能,那么这个REST控制器就没有被Spring Boot扫描到。 - Ravi
将"{[/send],methods=[GET],produces=[application/json]}"映射到公共的org.springframework.http.ResponseEntity<java.lang.String>。 - José Nobre
that appears :/ - José Nobre

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接