什么是Java 11 Cloud SDK的appengine:run等效命令?

huangapple go评论79阅读模式
英文:

What's the equivalent of appengine:run for the Java 11 Cloud SDK?

问题

tl;dr: 如何在本地运行这个项目,以使 Datastore 正常工作?我正在将一个使用 App Engine 和 Datastore 的 Java 8 项目迁移到 Java 11。在 Java 8 中,我使用基于 Cloud SDK 的 App Engine 插件 通过 mvn appengine:run 在本地运行服务器,并使用 mvn appengine:deploy 部署到实际服务器。我按照 这个指南 删除了 appengine-web.xml 文件,并改用 app.yaml。在实际服务器上部署时,我仍然可以使用 mvn appengine:deploy,这在有无 Datastore 的情况下都能正常工作。而在本地部署时,我运行 mvn package exec:java。这对于没有 Datastore 的基本服务器运行正常,但如果我添加了一些 Datastore 代码示例,那么就会出现以下错误:

java.lang.IllegalArgumentException: A project ID is required for this service but could not be determined from the builder or the environment. Please set a project ID using the builder.

我知道这是因为我没有运行本地的 App Engine 环境。但是,如果我尝试使用 mvn appengine:run 运行本地服务器,那么就会出现以下错误,指出缺少 appengine-web.xml 文件:

[ERROR] Failed to execute goal com.google.cloud.tools:appengine-maven-plugin:2.2.0:run (default-cli) on project datastore-hello-world:
Failed to run devappserver: java.nio.file.NoSuchFileException:
C:\Users\kevin\Documents\GitHub\HappyCoding\examples\google-cloud\google-cloud-example-projects\datastore-hello-world\target\datastore-hello-world-1\WEB-INF\appengine-web.xml -> [Help 1]

因此,我陷入了需要运行 mvn appengine:run(需要 appengine-web.xml)和需要升级到 Java 11(使用 app.yaml 替代 appengine-web.xml)之间。Java 11 App Engine 文档中关于本地运行的内容很少,只是提到:

在部署之前测试应用程序功能,使用通常使用的开发工具在本地环境中运行应用程序。

上述 GitHubzip 链接包含整个项目(共 5 个文件),但为了在问题中直接包含我的代码,以下是最重要的文件内容:

pom.xml

<!-- pom.xml 内容见原文 -->

ServerMain.java

// ServerMain.java 内容见原文

HelloWorldServlet.java

// HelloWorldServlet.java 内容见原文

如何在本地运行 Java 11 App Engine 服务器以使 Datastore 正常工作?

英文:

tl;dr: How can I run this project locally, in a way that Datastore will work? (Zip download link here.)

I'm migrating a Java 8 project that used App Engine and Datastore over to Java 11.

With Java 8, I used the Cloud SDK-based App Engine plugin to run the server locally using mvn appengine:run and to deploy to the live server using mvn appengine:deploy.

I followed this guide which told me to delete the appengine-web.xml file and use app.yaml instead..

To deploy to the live server, I can still use mvn appengine:deploy and this works fine, with and without Datastore.

To deploy locally, I run mvn package exec:java. This works fine for running a basic server without Datastore, but if I add some example Datastore code, then I get this error:

java.lang.IllegalArgumentException: A project ID is required for this service but could not be determined from the builder or the environment. Please set a project ID using the builder.

I know this is because I don't have a local App Engine environment running. But if I try to run the local server using mvn appengine:run then I get this error complaining about the missing appengine-web.xml file:

[ERROR] Failed to execute goal com.google.cloud.tools:appengine-maven-plugin:2.2.0:run (default-cli) on project datastore-hello-world:
Failed to run devappserver: java.nio.file.NoSuchFileException:
C:\Users\kevin\Documents\GitHub\HappyCoding\examples\google-cloud\google-cloud-example-projects\datastore-hello-world\target\datastore-hello-world-1\WEB-INF\appengine-web.xml -&gt; [Help 1]

So I'm stuck between needing to run mvn appengine:run which requires appengine-web.xml, and needing to update to Java 11, which says to use app.yaml instead of appengine-web.xml.

The Java 11 App Engine docs only say this about running locally:

> To test your application's functionality before deploying, run your application in your local environment with the development tools that you usually use.

The above GitHub and zip links contain the whole project (5 total files), but in the interest of including my code directly in the question, here are the files that matter the most:

pom.xml

&lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot;
    xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
    xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&gt;
  &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;

  &lt;groupId&gt;io.happycoding&lt;/groupId&gt;
  &lt;artifactId&gt;datastore-hello-world&lt;/artifactId&gt;
  &lt;version&gt;1&lt;/version&gt;

  &lt;properties&gt;
    &lt;!-- App Engine currently supports Java 11 --&gt;
    &lt;maven.compiler.source&gt;11&lt;/maven.compiler.source&gt;
    &lt;maven.compiler.target&gt;11&lt;/maven.compiler.target&gt;
    &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;
    &lt;jetty.version&gt;9.4.31.v20200723&lt;/jetty.version&gt;

    &lt;!-- Project-specific properties --&gt;
    &lt;mainClass&gt;io.happycoding.ServerMain&lt;/mainClass&gt;
    &lt;googleCloudProjectId&gt;YOUR_PROJECT_ID_HERE&lt;/googleCloudProjectId&gt;
  &lt;/properties&gt;

  &lt;dependencies&gt;
    &lt;!-- Java Servlets API --&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;javax.servlet&lt;/groupId&gt;
      &lt;artifactId&gt;javax.servlet-api&lt;/artifactId&gt;
      &lt;version&gt;4.0.1&lt;/version&gt;
    &lt;/dependency&gt;

    &lt;!-- Jetty --&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;org.eclipse.jetty&lt;/groupId&gt;
      &lt;artifactId&gt;jetty-server&lt;/artifactId&gt;
      &lt;version&gt;${jetty.version}&lt;/version&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;org.eclipse.jetty&lt;/groupId&gt;
      &lt;artifactId&gt;jetty-annotations&lt;/artifactId&gt;
      &lt;version&gt;${jetty.version}&lt;/version&gt;
    &lt;/dependency&gt;

    &lt;!-- Datastore --&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;com.google.cloud&lt;/groupId&gt;
      &lt;artifactId&gt;google-cloud-datastore&lt;/artifactId&gt;
      &lt;version&gt;1.104.0&lt;/version&gt;
    &lt;/dependency&gt;
  &lt;/dependencies&gt;

  &lt;build&gt;
    &lt;plugins&gt;
      &lt;!-- Copy static resources like html files into the output jar file. --&gt;
      &lt;plugin&gt;
        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
        &lt;artifactId&gt;maven-resources-plugin&lt;/artifactId&gt;
        &lt;version&gt;2.7&lt;/version&gt;
        &lt;executions&gt;
          &lt;execution&gt;
            &lt;id&gt;copy-web-resources&lt;/id&gt;
            &lt;phase&gt;compile&lt;/phase&gt;
            &lt;goals&gt;&lt;goal&gt;copy-resources&lt;/goal&gt;&lt;/goals&gt;
            &lt;configuration&gt;
              &lt;outputDirectory&gt;
                ${project.build.directory}/classes/META-INF/resources
              &lt;/outputDirectory&gt;
              &lt;resources&gt;
                &lt;resource&gt;&lt;directory&gt;./src/main/webapp&lt;/directory&gt;&lt;/resource&gt;
              &lt;/resources&gt;
            &lt;/configuration&gt;
          &lt;/execution&gt;
        &lt;/executions&gt;
      &lt;/plugin&gt;

      &lt;!-- Package everything into a single executable jar file. --&gt;
      &lt;plugin&gt;
        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
        &lt;artifactId&gt;maven-shade-plugin&lt;/artifactId&gt;
        &lt;version&gt;3.2.4&lt;/version&gt;
        &lt;executions&gt;
          &lt;execution&gt;
            &lt;phase&gt;package&lt;/phase&gt;
            &lt;goals&gt;&lt;goal&gt;shade&lt;/goal&gt;&lt;/goals&gt;
            &lt;configuration&gt;
              &lt;createDependencyReducedPom&gt;false&lt;/createDependencyReducedPom&gt;
              &lt;transformers&gt;
                &lt;transformer implementation=&quot;org.apache.maven.plugins.shade.resource.ManifestResourceTransformer&quot;&gt;
                  &lt;mainClass&gt;${mainClass}&lt;/mainClass&gt;
                &lt;/transformer&gt;
              &lt;/transformers&gt;
            &lt;/configuration&gt;
          &lt;/execution&gt;
        &lt;/executions&gt;
      &lt;/plugin&gt;

      &lt;!-- Exec plugin for deploying the local server. --&gt;
      &lt;plugin&gt;
        &lt;groupId&gt;org.codehaus.mojo&lt;/groupId&gt;
        &lt;artifactId&gt;exec-maven-plugin&lt;/artifactId&gt;
        &lt;version&gt;3.0.0&lt;/version&gt;
        &lt;executions&gt;
          &lt;execution&gt;
            &lt;goals&gt;
              &lt;goal&gt;java&lt;/goal&gt;
            &lt;/goals&gt;
          &lt;/execution&gt;
        &lt;/executions&gt;
        &lt;configuration&gt;
          &lt;mainClass&gt;${mainClass}&lt;/mainClass&gt;
        &lt;/configuration&gt;
      &lt;/plugin&gt;

      &lt;!-- App Engine plugin for deploying to the live site. --&gt;
      &lt;plugin&gt;
        &lt;groupId&gt;com.google.cloud.tools&lt;/groupId&gt;
        &lt;artifactId&gt;appengine-maven-plugin&lt;/artifactId&gt;
        &lt;version&gt;2.2.0&lt;/version&gt;
        &lt;configuration&gt;
          &lt;projectId&gt;${googleCloudProjectId}&lt;/projectId&gt;
          &lt;version&gt;1&lt;/version&gt;
        &lt;/configuration&gt;
      &lt;/plugin&gt;
    &lt;/plugins&gt;
  &lt;/build&gt;
&lt;/project&gt;

ServerMain.java

package io.happycoding;

import java.net.URL;
import org.eclipse.jetty.annotations.AnnotationConfiguration;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.webapp.Configuration;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.webapp.WebInfConfiguration;

/**
 * Starts up the server, including a DefaultServlet that handles static files,
 * and any servlet classes annotated with the @WebServlet annotation.
 */
public class ServerMain {

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

    // Create a server that listens on port 8080.
    Server server = new Server(8080);
    WebAppContext webAppContext = new WebAppContext();
    server.setHandler(webAppContext);

    // Load static content from inside the jar file.
    URL webAppDir =
        ServerMain.class.getClassLoader().getResource(&quot;META-INF/resources&quot;);
    webAppContext.setResourceBase(webAppDir.toURI().toString());

    // Enable annotations so the server sees classes annotated with @WebServlet.
    webAppContext.setConfigurations(new Configuration[]{ 
      new AnnotationConfiguration(),
      new WebInfConfiguration(), 
    });

    // Look for annotations in the classes directory (dev server) and in the
    // jar file (live server)
    webAppContext.setAttribute(
        &quot;org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern&quot;, 
        &quot;.*/target/classes/|.*\\.jar&quot;);

    // Handle static resources, e.g. html files.
    webAppContext.addServlet(DefaultServlet.class, &quot;/&quot;);

    // Start the server! &#128640;
    server.start();
    System.out.println(&quot;Server started!&quot;);

    // Keep the main thread alive while the server is running.
    server.join();
  }
}

HelloWorldServlet.java

package io.happycoding.servlets;

import com.google.cloud.datastore.Datastore;
import com.google.cloud.datastore.DatastoreOptions;
import com.google.cloud.datastore.Entity;
import com.google.cloud.datastore.Key;
import java.io.IOException;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(&quot;/hello&quot;)
public class HelloWorldServlet extends HttpServlet {

  @Override
  public void doGet(HttpServletRequest request, HttpServletResponse response)
      throws IOException {

    Datastore datastore = DatastoreOptions.getDefaultInstance().getService();

    String kind = &quot;Task&quot;;
    // The name/ID for the new entity
    String name = &quot;sampletask1&quot;;
    // The Cloud Datastore key for the new entity
    Key taskKey = datastore.newKeyFactory().setKind(kind).newKey(name);

    // Prepares the new entity
    Entity task = Entity.newBuilder(taskKey)
        .set(&quot;description&quot;, &quot;Buy milk&quot;)
        .build();

    // Saves the entity
    datastore.put(task);

    System.out.printf(&quot;Saved %s: %s%n&quot;, task.getKey().getName(), task.getString(&quot;description&quot;));

    //Retrieve entity
    Entity retrieved = datastore.get(taskKey);

    response.setContentType(&quot;text/html;&quot;);
    response.getWriter().println(&quot;&lt;h1&gt;Hello world!&lt;/h1&gt;&quot;);
    response.getWriter().println(&quot;Retrieved: &quot; + taskKey.getName() + &quot;: &quot; + retrieved.getString(&quot;description&quot;));
  }
}

How can I run a Java 11 App Engine server locally so that Datastore works?

答案1

得分: 0

基于guillaume blaquiere在他们的评论中的建议,我尝试按照此指南手动在本地运行Datastore。

我在一个命令行中运行了gcloud beta emulators datastore start,似乎运行正常,然后在另一个命令行中运行了$(gcloud beta emulators datastore env-init),然后我得到了这个错误:

错误:(gcloud.beta.emulators.datastore.env-init)
无法在数据目录[/tmp/tmp.zolNZC8fnr/emulators/datastore]中找到env.yaml。
请确保您已启动了适当的模拟器。

我回到了我运行Datastore的第一个命令行,在输出中我注意到了这一行:

存储:/tmp/tmp.sxkNeaNHxo/emulators/datastore/WEB-INF/appengine-generated/local_db.bin

我将那个目录路径复制到了data-dir参数中:

$(gcloud beta emulators datastore env-init --data-dir=/tmp/tmp.sxkNeaNHxo/emulators/datastore)

这个命令似乎成功了(没有输出),然后我运行了本地服务器:mvn package exec:java

最终,这在本地似乎是有效的。

总结一下:

步骤1: 运行以下命令:gcloud beta emulators datastore start

步骤2: 在输出中找到类似于以下内容的行:

存储:/tmp/tmp.sxkNeaNHxo/emulators/datastore/WEB-INF/appengine-generated/local_db.bin

复制/tmp/tmp.YOUR_PATH_HERE/emulators/datastore路径。

步骤3: 在另一个命令行中运行以下命令,并粘贴刚刚复制的路径:

$(gcloud beta emulators datastore env-init --data-dir=/tmp/tmp.YOUR_PATH_HERE/emulators/datastore)

步骤4: 在第二个命令行中,运行本地服务器:mvn package exec:java

这个过程看起来相当复杂(并且没有文档),所以我仍然非常愿意接受如何简化这个过程的建议。但暂时来说,至少这个方法有效。

英文:

Based on guillaume blaquiere's suggestion in their comment, I tried following this guide for manually running Datastore locally.

I ran gcloud beta emulators datastore start in one command line, which seemed to run fine, and then I ran $(gcloud beta emulators datastore env-init) in another command line, and I got this error:

ERROR: (gcloud.beta.emulators.datastore.env-init)
Unable to find env.yaml in the data_dir 
[/tmp/tmp.zolNZC8fnr/emulators/datastore]. 
Please ensure you have started the appropriate emulator.

I went back to the first command line where I ran Datastore, and I noticed this line in the output:

Storage: /tmp/tmp.sxkNeaNHxo/emulators/datastore/WEB-INF/appengine-generated/local_db.bin

I copied that directory path into the data-dir argument:

$(gcloud beta emulators datastore env-init --data-dir=/tmp/tmp.sxkNeaNHxo/emulators/datastore)

That command seemed to succeed (with no output) so I ran my local server: mvn package exec:java

Finally, this seems to work locally.

To summarize:

Step 1: Run this command: gcloud beta emulators datastore start

Step 2: In the output, find the line that looks like this:

Storage: /tmp/tmp.sxkNeaNHxo/emulators/datastore/WEB-INF/appengine-generated/local_db.bin

Copy the /tmp/tmp.YOUR_PATH_HERE/emulators/datastore path.

Step 3: In a different command line, run this command, pasting in the path you just copied:

$(gcloud beta emulators datastore env-init --data-dir=/tmp/tmp.YOUR_PATH_HERE/emulators/datastore)

Step 4: In that second command line, run your local server: mvn package exec:java

This feels pretty convoluted (and undocumented), so I'm still very open to suggestions for how to streamline this. But for now, this at least works.

答案2

得分: 0

你可以在本地使用Java 11以与Java 8相同的方式使其全部运行。但是你需要保留传统捆绑服务:https://cloud.google.com/appengine/docs/standard/java-gen2/services/access#java-11

  • 因此,您仍然需要一个appengine-web.xml文件,该文件由gcloud转换为暂存目录中的app.yaml文件。

  • 您需要在appengine-web.xml文件中添加<app-engine-apis>true</app-engine-apis>

  • 我还需要确保我的pom.xml文件中包含了最新的maven gcloud、appengine SDK和其他依赖项。

英文:

You can keep it all running locally in Java 11 in the same way it all worked for Java 8.
But you need to keep the Legacy Bundled Services:
https://cloud.google.com/appengine/docs/standard/java-gen2/services/access#java-11

  • So you still have a appengine-web.xml which gcloud coverts to an app.yaml in the staging directory
  • You need to add &lt;app-engine-apis&gt;true&lt;/app-engine-apis&gt; to your appengine-web.xml file.
  • I also needed to ensure I had the latest maven gcloud, appengine SDK, and other dependencies in my pom.xml file.

huangapple
  • 本文由 发表于 2020年8月17日 13:29:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/63445036.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定