1

我正在开发一个 REST-API,目前正在尝试解决一个问题。问题是当我在 chrome 中访问我的网页时,REST-API 无法连接到 pgsql 数据库。为了说明这个问题,我将发布我的堆栈的精简版本并附上一些解释,描述所涉及的 Java 类和 XML 的起源和功能。之后,我将展示一些涉及的 ​​XML 文件和 java 类的代码。我期待您对我的第一篇文章的回答和反馈。

更新:在帖子的最后,我将披露我在寻找答案方面的主要进展。

到目前为止,我正在使用以下工具:

  • Eclipse EE(目前是 Oxygen II)
  • Apache Tomcat 8.5.14
  • 马文
  • 铬合金
  • PG-管理员 4

堆栈从这条线开始,这可能意味着泽西遇到了一些困难。

WARNING: The following warnings have been detected: WARNING: Unknown HK2 failure detected:

我的堆栈继续出现下面所示的 java.lang.ExceptionInInitializerError,它源自我的数据库连接代理。

MultiException stack 1 of 2
java.lang.ExceptionInInitializerError
at nl.hu.v1wac.PostgresDAO.webservices.WorldResource.<init (WorldResource.java:25) 
Caused by: java.lang.RuntimeException: javax.naming.NameNotFoundException: Name [jdbc/PostgresDS] is not bound in this Context. Unable to find [jdbc].
at nl.hu.v1wac.PostgresDAO.jdbc.BaseDAO.<init>(BaseDAO.java:38)
at nl.hu.v1wac.PostgresDAO.jdbc.CountryDAO.<init>(CountryDAO.java:13)
at nl.hu.v1wac.PostgresDAO.model.WorldService.<init>(WorldService.java:9)
at nl.hu.v1wac.PostgresDAO.model.ServiceProvider.<clinit>(ServiceProvider.java:4)
... 61 more

多堆栈中的第二个异常是 IllegalStateException,它源自我的 WorldResource 类,包含统一资源标识符和 JSON 解释器,用于将 json 消息解析到我的前端。

MultiException stack 2 of 2
java.lang.IllegalStateException: Unable to perform operation: create on nl.hu.v1wac.PostgresDAO.webservices.WorldResource
Caused by: java.lang.RuntimeException: javax.naming.NameNotFoundException: 
at org.jvnet.hk2.internal.ClazzCreator.create(ClazzCreator.java:393)
at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:427)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:388)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)

下面我将展示我的 web.xml。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
  <display-name>MavenJersey</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  <servlet>
    <servlet-name>Jersey REST Service</servlet-name>
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
    <init-param>
      <param-name>jersey.config.server.provider.packages</param-name>
      <param-value>nl.hu.v1wac.PostgresDAO.webservices</param-value>
    </init-param>
    <init-param>
      <param-name>jersey.config.server.provider.classnames</param-name>
      <param-value>org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature</param-value>
    </init-param>
    <load-on-startup>2</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>Jersey REST Service</servlet-name>
    <url-pattern>/restservices/*</url-pattern>
  </servlet-mapping>
</web-app>

下面将展示我的 BaseDAO。此类是我的数据访问对象的连接代理。

import java.sql.Connection;
import javax.naming.InitialContext;
import javax.sql.DataSource;
import java.net.URI;
import org.apache.tomcat.dbcp.dbcp2.BasicDataSource;

public class BaseDAO {
    private static final String URL = "jdbc:postgresql://";
    private static final String JDBC_DRIVER = "org.postgresql.Driver";
    private static final String CONTEXT = "java:comp/env/jdbc/PostgresDS";
    private DataSource connectionPool;
    public BaseDAO() {
    try {
        final String DATABASE_URL_PROP = System.getenv("DATABASE_URL");
        if (DATABASE_URL_PROP != null) {
            URI dbUri = new URI(DATABASE_URL_PROP);
            String dbUrl = URL + dbUri.getHost() + dbUri.getPath();
            BasicDataSource pool = new BasicDataSource();

            if (dbUri.getUserInfo() != null) {
                pool.setUsername(dbUri.getUserInfo().split(":")[0]);
                pool.setPassword(dbUri.getUserInfo().split(":")[1]);
                }
                pool.setDriverClassName(JDBC_DRIVER);
                pool.setUrl(dbUrl);
                pool.setInitialSize(1);

                connectionPool = pool;

        } else{
            InitialContext ic = new InitialContext();
            connectionPool = (DataSource) ic.lookup(CONTEXT);
        }
    } catch (Exception e) {

      throw new RuntimeException(e);
    }
    }
  protected final Connection getConnection() {
      try {
          return connectionPool.getConnection();
      } catch (Exception ex) {
          throw new RuntimeException(ex);
      }
  }
}

最后,我将以我的 WorldResource 课程结束这篇文章。请注意,大多数代码都被排除在外。

public class WorldResource{
    private WorldService service = ServiceProvider.getWorldService();    
@GET
@RolesAllowed({"admin"})
@Path("/getAll")
@Produces(MediaType.APPLICATION_JSON)
public String getCountries() {
        JsonArrayBuilder jab;
        jab = Json.createArrayBuilder();
        for (Country c : service.getAllCountries()) {
            jab.add(makeCountryObj(c));
        }
        return jab.build().toString();
}

编辑: @Alok Sinha 发布 context.xml 丢失后,我添加了我已经存在的 context.xml 以提供一些额外的见解。

<?xml version="1.0" encoding="UTF-8"?> 
<Context> <Resource name="jdbc/PostgresDS" 

url="jdbc:postgresql://localhost:5432/mydb" driverClassName="org.postgresql.Driver" 
auth="Container" 
type="javax.sql.DataSource" 
username="javaduser" 
password="javadude" 
/> 
<ResourceLink name="jdbc/PostgresDS" global="jdbc/PostgresDS" type="javax.sql.DataSource" 
/>
</Context>

更新:在向我的 web.xml 添加资源引用后,由Apache 手册推荐,我能够对我的连接问题获得一些新的见解。

  <resource-ref>
    <description>PostgreSQL Datasource example</description>
    <res-ref-name>jdbc/PostgresDS</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
  </resource-ref>

如下面的堆栈所示,添加资源引用似乎有助于将我的应用程序指向正确的方向。但是,名称和 url 似乎是空的。

Cannot create JDBC driver of class '' for connect URL 'null'
java.sql.SQLException: No suitable driver
at java.sql.DriverManager.getDriver(Unknown Source)
at nl.hu.v1wac.PostgresDAO.jdbc.BaseDAO.getConnection(BaseDAO.java:47)
at nl.hu.v1wac.PostgresDAO.webservices.WorldResource.getCountries(WorldResource.java:34)

UPDATE2: 我尝试了另一种方法。我从一个最初的 Maven 项目开始,然后从那里构建我的应用程序。我摆脱了 IllegalstateException。我已经完全按照Alok Sinha的描述实现了您的 context.xml。所以,没有资源链接。我还把 BaseDAO 脱掉到只有 Initialcontext 和 Datasource 的地步。现在我可以在没有 basedao 的情况下将应用程序部署为 war 文件。如果我尝试使用 BaseDAO 部署它,由于我的 tomcat 日志中出现以下错误,我无法运行:

org.apache.catalina.deploy.NamingResourcesImpl.cleanUp Failed to retrieve
JNDI naming context for container [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/holidayboardapp]] so no cleanup was performed for that container 
  javax.naming.NameNotFoundException: Name [comp/env] is not bound in this Context. Unable to find [comp].`
4

2 回答 2

2

看来您还没有将数据源绑定到 tomcat 的 JNDI 中。您需要在 context.xml 中输入一个条目,如下所示 -

<Resource name="jdbc/PostgresDS" auth="Container" type="javax.sql.DataSource"
           maxActive="100" maxIdle="30" maxWait="10000"
           username="javauser" password="javadude" driverClassName="org.postgresql.Driver"
           url="jdbc:postgresql:localhost..."/>
于 2018-04-04T14:31:26.913 回答
0

与我最初的问题相比,解决方案取决于我如何部署我的应用程序。起点。下面我将描述我在此过程中学到的两个起点。

一个起点是使用 Eclipse EE 部署应用程序,然后 Eclipse 将其部署在我的 Tomcat 根文件夹上的 wtpwebapps 上。Eclipse 将您的应用程序部署在 wtpwebapps 文件夹中。然后,每个应用程序都将作为 server.xml<Host>中的下级引用。这个stackoverflow帖子也提到了这个答案。

<Host appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="true">

另一个起点是直接在 tomcat webapps 文件夹上部署我的应用程序或使用 tomcat 管理器,我将在我的 maven 构建中包含 context.xml,就像 Alok Sinha 正确告诉我的那样。然后 Tomcat 将为我进行部署。

以我个人的经验,你必须决定你喜欢哪个起点。如果您想使用 Eclipse 来执行此操作,则不能使用 tomcat 管理器取消部署或重新部署应用程序,因为应用程序的上下文将被硬编码在 server.xml 中。如果您仍想这样做,则必须从 server.xml 中手动从应用程序中删除上下文。

于 2018-04-16T18:06:50.280 回答