如何使用Java(桌面版)将数据保存到Firebase

3
我正在尝试使用Java编写的桌面应用程序将数据保存到Firebase。但是,由于某些原因它不起作用,我一直在遵循这里提供的文档:https://firebase.google.com/docs/database/admin/save-data。我找不到任何关于此问题的视频教程,所有视频都与Web或移动相关。基本上,我想创建一个名为Venda的对象,该对象具有3个属性(ID、data、valor),然后将其保存到Firebase中。谢谢!
以下是主要方法:
public class Main {

    public static void main(String[] args) throws IOException, InterruptedException {
        System.out.println("--------- Begin of Output ---------");
        Firebase firebase = new Firebase();
        VendasCRUD venda = new VendasCRUD(firebase);
        venda.createVenda(new Venda(0, "23/05/1993", 45.67));
        System.out.println("----------- End of Output -----------");
    }

}

Firebase连接:
public class Firebase {

    public Firebase() throws FileNotFoundException, IOException {
        FileInputStream serviceAccount = new FileInputStream("C:\\Users\\Alex\\Documents\\NetBeansProjects\\SEMS\\src\\main\\java\\br\\com\\sems\\firebase\\sems-firebase.json");

        FirebaseOptions options = new FirebaseOptions.Builder()
                .setCredentials(GoogleCredentials.fromStream(serviceAccount))
                .setDatabaseUrl("https://sems-firebase.firebaseio.com/")
                .build();

        FirebaseApp.initializeApp(options);
    }

    public DatabaseReference getDataBaseReference() {
        return FirebaseDatabase.getInstance().getReference();
    }

}

销售类:

public class Venda {

    public int ID;
    public String data;
    public double valor;

    public Venda(int ID, String data, double valor) {
        this.ID = ID;
        this.data = data;
        this.valor = valor;
    }

    @Override
    public String toString() {
        return ID + "," + data + "," + valor;
    }

}

数据库信息:

enter image description here

目前规则已设置为公开,用于测试目的。


更新:

好的,在尝试了FrankvanPuffelen评论中提出的建议后,我仍然无法保存或读取Firebase中的数据。我编写了一个简单的测试代码。以下是代码:

public class Main {

    private static final String DATABASE_URL = "https://sems-firebase.firebaseio.com/";
    private static DatabaseReference database;
    private static boolean finished = false;

    public static void startListeners() {
        database.child("posts").addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                Post post = dataSnapshot.getValue(Post.class);
                System.out.println(post);
                finished = true;
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {
                System.out.println("The read failed: " + databaseError.getCode());
            }
        });
        while(!finished);
    }

    public static void main(String[] args) throws FileNotFoundException {

        try {
            FileInputStream serviceAccount = new FileInputStream("sems-firebase.json");
            FirebaseOptions options = new FirebaseOptions.Builder()
                    .setCredentials(GoogleCredentials.fromStream(serviceAccount))
                    .setDatabaseUrl(DATABASE_URL)
                    .build();



        FirebaseApp defaultApp =  FirebaseApp.initializeApp(options);
        FirebaseDatabase defaultDatabase = FirebaseDatabase.getInstance(defaultApp);

        System.out.println(defaultDatabase.getReference().toString());

    } catch (IOException e) {
        System.out.println("ERROR: invalid service account credentials. See README.");
        System.out.println(e.getMessage());

        System.exit(1);
    }

    // Shared Database reference
    database = FirebaseDatabase.getInstance().getReference();

    // Start listening to the Database
    startListeners();

}

}

所以我一直在做的就是,运行代码然后转到数据库网址并手动编辑帖子,我期望在控制台上得到我刚刚编辑的帖子的打印输出,但是什么也没有发生。
以下是数据库的快照: enter image description here

更新2

我认为这里提出的建议:为什么Firebase Java SDK无法在设置后终止?已经过时,因为如果我尝试使用以下代码:

enter image description here

我尝试将它修改为这样:

public static void startListeners() throws InterruptedException {
    DatabaseReference database = FirebaseDatabase.getInstance().getReference("posts/adad2131/author");
    CountDownLatch done = new CountDownLatch(1);
    database.setValue("Test", new DatabaseReference.CompletionListener() {
        @Override
        public void onComplete(DatabaseError de, DatabaseReference dr) {
            done.countDown();
        }
    });
    done.await();
}

但是 onComplete 方法从未执行,程序也从未结束。至于在此提出的建议:java Firebase: delay exit until writes finish 也可能已被弃用,因为似乎 CompletionListener() 不再存在于 Firebase 中,但我可以在 DatabaseReference 中找到它,所以我将代码修改为以下内容:
private static final String DATABASE_URL = "https://sems-firebase.firebaseio.com/";

public static void startListeners() throws InterruptedException {
    DatabaseReference database = FirebaseDatabase.getInstance().getReference("posts/adad2131/author");
    final AtomicBoolean done = new AtomicBoolean(false);
    database.setValue("Test", new DatabaseReference.CompletionListener() {
        @Override
        public void onComplete(DatabaseError de, DatabaseReference dr) {
            done.set(true);
        }
    });
    while (!done.get());
}

与之前一样,onComplete方法从未被执行,程序也从未完成或将数据设置到数据库中。这是我正在尝试修改的帖子的快照:

enter image description here


更新 3

为了方便使用,我简化了代码。为了确保,我从项目的服务帐户面板生成了一个新的私钥,这是我初始化应用程序的方法:

    try {
        FileInputStream serviceAccount = new FileInputStream("sems-firebase-firebase-adminsdk-gamnp-874087bbd1.json");
        FirebaseOptions options = new FirebaseOptions.Builder()
                .setCredentials(GoogleCredentials.fromStream(serviceAccount))
                .setDatabaseUrl("https://sems-firebase.firebaseio.com/")
                .build();

        FirebaseApp.initializeApp(options);

    } catch (IOException e) {
        System.out.println("ERROR: invalid service account credentials.");
        System.out.println(e.getMessage());

        System.exit(1);
    }

这是数据库的快照,我试图更改的值是帖子ID为“adad2131”的作者字段。

enter image description here

我已经尝试使用“posts/adad2131/author”,“/posts/adad2131/author”或者仅仅是“adad2131/author”来引用该字段,也许我引用方式不正确吗?
以下是完整的代码:
public class Main {

    public static void main(String[] args) throws FileNotFoundException, InterruptedException {

        try {
            FileInputStream serviceAccount = new FileInputStream("sems-firebase-firebase-adminsdk-gamnp-874087bbd1.json");
            FirebaseOptions options = new FirebaseOptions.Builder()
                    .setCredentials(GoogleCredentials.fromStream(serviceAccount))
                    .setDatabaseUrl("https://sems-firebase.firebaseio.com/")
                    .build();

            FirebaseApp.initializeApp(options);

        } catch (IOException e) {
            System.out.println("ERROR: invalid service account credentials.");
            System.out.println(e.getMessage());

            System.exit(1);
        }

        //Try to change data in Firebase
        CountDownLatch done = new CountDownLatch(1);
        FirebaseDatabase.getInstance().getReference("posts/adad2131/author").setValue("Test", new DatabaseReference.CompletionListener() {
            @Override
            public void onComplete(DatabaseError de, DatabaseReference dr) {
                done.countDown();
            }
        });
        done.await();

    }
}

Ps. 我也正在使用管理员 SDK 5.9


1
很可能你的Java程序在Firebase写入数据之前就已经退出了。典型的解决方案是添加延迟(非常简单)或使用信号量来指示何时完成写入(更好的方式)。让我找一个已经有一些示例的问题。 - Frank van Puffelen
1
示例:https://stackoverflow.com/questions/45253891/why-firebase-java-sdk-cant-terminate-after-set,https://stackoverflow.com/questions/26092632/java-firebase-delay-exit-until-writes-finish,https://groups.google.com/forum/#!searchin/firebase-talk/exit$20java/firebase-talk/BHa8M9YE1RE/aW4dwn_pZ88J - Frank van Puffelen
我一回到家就会查看你发布的链接并给出反馈,谢谢。 - Alexandre Krabbe
所以我已经阅读了答案并尝试了提出的两个解决方案。第一个确实使程序停止了,但它从未设置数据或完成程序。对于第二个解决方案,它使用来自com.firebase.client.Firebase的Firebase.CompletionListener(); 但是,由于某种原因,maven找不到该依赖项。我无法打开第三个链接,您认为我尝试插入数据库的方式有问题吗? - Alexandre Krabbe
没有看到您的更新代码,很难知道发生了什么。 - Frank van Puffelen
显示剩余6条评论
1个回答

3

我刚刚将您的代码复制到了使用Firebase Admin SDK 5.9的项目中并运行,它顺利地写入了数据库。

CountDownLatch done = new CountDownLatch(1);
FirebaseDatabase.getInstance().getReference("49723347").setValue("Test", new DatabaseReference.CompletionListener() {
    @Override
    public void onComplete(DatabaseError de, DatabaseReference dr) {
        done.countDown();
    }
});
done.await();

你可以在这里看到结果:https://stackoverflow.firebaseio.com/49723347.json 引用49723347是我的数据库路径(它是您问题的ID)。我没有做其他更改。
因此,似乎问题不在我们一直查看的代码中。以下是我初始化应用程序的方式:
FileInputStream serviceAccount = new FileInputStream("stackoverflow-3d9889aaeddb.json");

FirebaseOptions options = new FirebaseOptions.Builder()
        .setCredential(FirebaseCredentials.fromCertificate(serviceAccount))
        .setDatabaseUrl("https://stackoverflow.firebaseio.com/")
        .build();

FirebaseApp.initializeApp(options);

你确定这个配置是针对你正在编写的项目的吗?



我的唯一线索是我可能引用了作者字段错误,我添加了一个更新3部分展示我所做的。 - Alexandre Krabbe
在我看来基本上是一样的。你确定你能够调用setValue吗?如果你在调试器中运行并在那一行设置断点,它会被触发吗? - Frank van Puffelen
我确实这样做了,setValue()行上的断点得到了触发,然后它执行了done.await(),但永远不会完成,因为onComplete()从未被触发。我还尝试在onComplete()上设置断点,输出如下:Listening on 55920 User program running Not able to submit breakpoint LineBreakpoint Main.java:38, reason: No executable location available at line 38 in class br.com.firebasetest.Main$1. Invalid LineBreakpoint Main.java:38 - Alexandre Krabbe
Frank,在文档中指出:“Firebase Admin Java SDK已发布到Maven中央存储库。要安装库,请在build.gradle文件中声明它作为依赖项” dependencies { compile 'com.google.firebase:firebase-admin:5.9.0' } 我从未这样做过,我只是在我的pom.xml文件中添加了<dependency> <groupId>com.google.firebase</groupId> <artifactId>firebase-admin</artifactId> <version>5.9.0</version> </dependency>。此外,我尝试更改数据库中的值,我知道它可以工作,所以问题不在数据库上。 - Alexandre Krabbe
所以我认为这将缩小到我的本地机器上的某些配置,有什么想法吗? - Alexandre Krabbe
显示剩余6条评论

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