spring jpa - 必须至少有一个JPA元模型*

时间:2017-04-06 12:24:45

标签: java sql-server spring-boot spring-data-jpa spring-rest

有人知道它为什么不起作用吗?

com.cadit.entities

我在import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name="TEST") public class GenericBeans implements BeanType, IEntity<Long> { /** * */ private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name = "TEST_PAID") protected Long id; @Column(name = "SOCIETA") private String SocietaCod; @Column(name = "CONTO_INTERMEDIARIO") private String contoInt; @Column(name = "TIPO_OPERAZIONE") private String tipoOpe; public GenericBeans(String societaCod, String contoInt, String tipoOpe) { SocietaCod = societaCod; this.contoInt = contoInt; this.tipoOpe = tipoOpe; } public GenericBeans() { } public String getSocietaCod() { return SocietaCod; } public void setSocietaCod(String societaCod) { SocietaCod = societaCod; } public String getContoInt() { return contoInt; } public void setContoInt(String contoInt) { this.contoInt = contoInt; } public String getTipoOpe() { return tipoOpe; } public void setTipoOpe(String tipoOpe) { this.tipoOpe = tipoOpe; } @Override public String toString() { return "CSV [SocietaCod=" + SocietaCod + ", contoInt=" + contoInt + ", tipoOpe=" + tipoOpe + "]"; } @Override public Long getId() { return this.id; } @Override public void setId(Long id) { this.id=id; } } 中定义了实体:

datasource

我为spring import org.apache.log4j.Logger; import org.springframework.boot.autoconfigure.domain.EntityScan; import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.transaction.annotation.EnableTransactionManagement; @Configuration @ComponentScan @EntityScan("com.cadit.entities") //@EnableJpaRepositories("com.cadit.entities") @EnableTransactionManagement @PropertySource("classpath:db-config.properties") public class DbAutoConfiguration { static final Logger logger = Logger.getLogger(DbAutoConfiguration.class); public DbAutoConfiguration() { } @Bean @ConfigurationProperties(prefix = "spring.datasource") public DataSource dataSource(){ //DataSource ds =new EmbeddedDatabaseBuilder().addScript("classpath:sql/schema.sql").addScript("classpath:testdb/data.sql").build(); DataSourceBuilder ds = DataSourceBuilder.create(); logger.info("dataSource = " + ds); return ds.build(); } } 明确了db-config.properties条目定义

spring.jpa.hibernate.ddl-auto: validate
spring.jpa.hibernate.naming_strategy: org.hibernate.cfg.ImprovedNamingStrategy
#spring.jpa.database: SQL
spring.jpa.show-sql: true

spring.datasource.driverClassName=net.sourceforge.jtds.jdbc.Driver
spring.datasource.url=jdbc:jtds:sqlserver://localhost:1433;databaseName=example
spring.datasource.username=xxx
spring.datasource.password=xxx

我的IEntity是:

public interface IEntity <I extends Serializable> extends Serializable{

/**
  * Property rappresenta la primary key.
  */
  String P_ID = "id";

  /**
   * restituisce la primary key
   * @return
   */
  I getId();

  /**
   * imposta la primary key
   * @param id
   */
  void setId(I id);
}

CrudRepository是:

import java.io.File;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.repository.CrudRepository;

import com.cadit.entities.GenericBeans;
import com.csvreader.CsvReader;

public class CsvReaders {

    static final Logger logger = Logger.getLogger(CsvReader.class);

    @Autowired
    public CrudRepository<GenericBeans,Long> _entitymanager;

    public List loadDataFromCsv(String fileName) {
        try {

            File file = new ClassPathResource(fileName).getFile();
            CsvReader csv = new CsvReader(file.getAbsoluteFile().getPath(),';');
            csv.readHeaders();
            List l = new LinkedList();
            GenericBeans b = new GenericBeans ();
            while (csv.readRecord())
            {
                b.setSocietaCod(csv.get(0));
                b.setContoInt(csv.get(1));
                b.setTipoOpe(csv.get(2));
                _entitymanager.save(b); //persist on db
                l.add(b);
                b = new GenericBeans();
            }
            b=null;
            return l;
        } catch (Exception e) {
            logger.error("Error occurred while loading object list from file " + fileName, e);
            return Collections.emptyList();
        }
    }


} 

我尝试使用spring的main接口将CSV文件写入数据库:

SpringBootServletInitializer

我不使用import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.web.support.SpringBootServletInitializer; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan(basePackages={"com.cadit.entities","com.cadit.beans"}) @EnableAutoConfiguration public class WebApplicationAware extends SpringBootServletInitializer { private static Class<WebApplicationAware> applicationClass = WebApplicationAware.class; public static void main(String[] args) { SpringApplication.run(applicationClass, args); } @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(applicationClass); } } 类,而是使用扩展pom.xml的类,因为我想在独立的tomcat和Tomcat安装上运行它作为WAR应用程序

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.springframework</groupId>
    <artifactId>xxxx</artifactId>
    <version>0.1.0</version>
    <packaging>war</packaging>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.2.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId> 
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.jayway.jsonpath</groupId>
            <artifactId>json-path</artifactId>
            <scope>test</scope>
        </dependency>
       <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-jpa</artifactId>
        <version>1.11.1.RELEASE</version>
    </dependency>
    <dependency> 
        <groupId>javax.persistence</groupId> 
        <artifactId>persistence-api</artifactId> 
        <version>1.0.2</version> 
    </dependency> 


        <!-- altre dipendenze non spring -->
        <!-- https://mvnrepository.com/artifact/net.sourceforge.javacsv/javacsv -->
        <dependency>
            <groupId>net.sourceforge.javacsv</groupId>
            <artifactId>javacsv</artifactId>
            <version>2.0</version>
        </dependency>

        <!--  per jpa solo se si usa il Tomcat embedded -->
        <dependency>
            <groupId>net.sourceforge.jtds</groupId>
            <artifactId>jtds</artifactId>
            <version>1.3.1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-dbcp2</artifactId>
            <version>2.1.1</version>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.0</version>
            <scope>provided</scope>
        </dependency>
        <!--  end -->


         <!-- dipendenze logback -->
      <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.5</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jcl-over-slf4j</artifactId>
            <version>1.7.5</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.1.7</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <version>1.1.7</version>
        </dependency>

        <!-- fine dip logback -->

    </dependencies>

    <properties>
     <start-class>hello.WebApplicationAware</start-class>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>


    <build>

   <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>

    <repositories>
        <repository>
            <id>spring-releases</id>
            <url>https://repo.spring.io/libs-release</url>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>spring-releases</id>
            <url>https://repo.spring.io/libs-release</url>
        </pluginRepository>
    </pluginRepositories>
</project>

所有属性文件都在classpath资源中,因为它是一个maven项目。

<?php

<?php

session_start();

if (!isset($_SESSION["user"])) {

    $logged_in = "no";

} else {

    $username = $_SESSION["user"];
    $logged_in = "yes";

}

include ('global.php');

?>

问题是什么,为什么我在运行WebApplicationAware类时找不到JPA实体?

3 个答案:

答案 0 :(得分:10)

Spring没有找到任何JPA实体,因此没有创建JPA元模型,这就是你面对异常的原因。

此问题的原因可能是类路径上的persistence-api版本错误。

您正在使用

<dependency> 
    <groupId>javax.persistence</groupId> 
    <artifactId>persistence-api</artifactId> 
    <version>1.0.2</version> 
</dependency> 

但我非常害羞你的spring版本使用了persistence-api版本2.

可能是,您正在使用版本1中的@Entity注释吗? 在运行时spring使用版本2,这是仅使用版本2中的@Entity搜索Entites!

删除依赖项

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-test</artifactId>
   <scope>test</scope>
</dependency>    
<dependency>
   <groupId>org.springframework.data</groupId>
   <artifactId>spring-data-jpa</artifactId>
   <version>1.11.1.RELEASE</version>
</dependency>

改为添加

  <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-data-jpa</artifactId>
  </dependency>

这将为您提供正确版本中的所有JPA依赖项。

答案 1 :(得分:1)

我通过添加2个注释解决了它

@EnableAutoConfiguration
@EntityScan(basePackages = { "com.wt.rds" })

我的依赖已成定局

compile group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa', version: '2.0.4.RELEASE'

答案 2 :(得分:0)

不幸的是,大多数有关JPA集成测试的springboot指南经常在这里和那里缺少一些配置。

所以这里有一个例子,希望它能为您服务。

第1点。 我的本地环境当前已设置为使用springboot版本:

<version.spring.boot>1.5.9.RELEASE</version.spring.boot>

话虽如此,我目前正在设置本地环境,以便能够对多个数据库(例如postgres,hsql,h2)运行集成测试。 因此,我首先搜索所有解决此问题的随机小圆面包。

下一个链接就是这样一个示例:

  

https://www.baeldung.com/spring-testing-separate-data-source

以上示例是一个很好的起点。它允许您获取有效的实体和有效的存储库。另一方面,springboot测试类本身却有很多不足之处。

在上面的示例中,您将立即进行集成测试。您将得到有关该示例的不可用问题,该示例未提供给您application.class来配置集成测试,并且您对于需要放置在何处以使测试最终运行而不会爆炸的springboot注释一无所知。

因此,现在我为您提供3个类的最小集(实体+存储库+ SpringbootTest),希望它们可以具有所需配置的100%。这将作为您将来需要进行的任何基于JPA的集成测试的基础,然后您可以交换您的实体和存储库,并继续使用相同类型的srpingboot配置进行测试。

我首先为您提供IRRELEVANT类。总是相同的东西,要测试的东西,与配置无关。 我指的是仓库+实体。

在eclipse中创建您的Java包: tutorial.www.baeldung.com.tutorial001jpa.separateDS

将以下琐碎的实体和存储库类转储到此程序包中,这些类是基于我在上面给出的教程参考得出的。

Tutorial001GenericEntity

package tutorial.www.baeldung.com.tutorial001jpa.separateDS;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "TUTORIAL_001_GENERIC_ENTITY")
public class Tutorial001GenericEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String value;

    public Tutorial001GenericEntity() {
        super();
    }

    public Tutorial001GenericEntity(String value) {
        super();
        this.value = value;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    // standard constructors, getters, setters

}

然后我们去看第二个平凡的代码片段。 弹簧仓库样板代码。

Tutorial001GenericEntityRepository


package tutorial.www.baeldung.com.tutorial001jpa.separateDS;

import org.springframework.data.jpa.repository.JpaRepository;

public interface Tutorial001GenericEntityRepository extends JpaRepository<Tutorial001GenericEntity, Long> {

}

这时,您的maven项目src / test / java共有两个类。基本的东西。 一个实体和一个存储库,可以作为您将需要进行的任何集成测试的示例。

因此,现在您进入示例中唯一重要的类,该类始终会带来很多问题,这就是springboot测试类,该类不仅负责测试您的业务逻辑,而且还具有配置的复杂任务。您的测试。

在这种情况下,该测试类具有ALL ALL ONE的批注,这些批注允许springboot破坏您的实体,存储库等...

package tutorial.www.baeldung.com.tutorial001jpa.separateDS;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = {
        tutorial.www.baeldung.com.tutorial001jpa.separateDS.Tutorial001GenericEntityIntegrationTest.ConfigureJpa.class })
@SpringBootTest()
public class Tutorial001GenericEntityIntegrationTest {

    @EntityScan(basePackageClasses = { Tutorial001GenericEntity.class })
    @EnableJpaRepositories(basePackageClasses = Tutorial001GenericEntity.class)
    @EnableAutoConfiguration()
    public static class ConfigureJpa {

    }

    @Autowired
    private Tutorial001GenericEntityRepository genericEntityRepository;

    @Test
    public void givenTutorial001GenericEntityRepository_whenSaveAndRetreiveEntity_thenOK() {
        Tutorial001GenericEntity genericEntity = genericEntityRepository.save(new Tutorial001GenericEntity("test"));
        Tutorial001GenericEntity foundEntity = genericEntityRepository.findOne(genericEntity.getId());

        assertNotNull(foundEntity);
        assertEquals(genericEntity.getValue(), foundEntity.getValue());
    }
}

您所看到的重要一点是,该Spring Boot测试具有一个类级别的注释,可为springboot测试提供配置上下文。

我们正在做的是转储一个且仅一个代表我们测试配置的类引用。     tutorial.www.baeldung.com.tutorial001jpa.separateDS.Tutorial001GenericEntityIntegrationTest.ConfigureJpa.class

然后,在这个小家伙上,您将springboot提供的所有其他注释放置到配置应用程序中。

在这种情况下,我们有专门的注释来提及实体。 另一个要提到的仓库。 另一个告诉springboot激活其自动配置。

然后,此springboot自动配置批注会执行其他伏都教,例如查看您的类路径并看到您在类路径中说:

   <dependency>
        <groupId>org.hsqldb</groupId>
        <artifactId>hsqldb</artifactId>
        <scope>test</scope>
        <version>2.3.4</version>
    </dependency>

它将立即知道如何为此数据库配置内存数据源。

在幕后,可能会使用其他配置。 例如,如果您在src / test / resources中创建一个application.properties文件,则将考虑该文件。 很高兴看到正在运行的测试考虑了appliction.properties。

如果要验证这一点,请确保例如在测试设置中没有对postgres的JDBC驱动程序的任何依赖。 然后在您的application.properties中添加一些类似的内容:

spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect

该方言与HSQL或H2不兼容,因此将立即使您通过绿色集成测试失败。

说实话,我不知道是否有一个更简单的批注组合来正确配置springboot扫描以进行集成测试。

通常,我建议您避免在src / test / resources中避免成千上万个配置类。 因为如果某个时候您想将所有集成测试从使用applicat-postgres.proeprties切换到application-hsql.properties,那么您可能会发现自己需要调整多个配置类,而不仅仅是一个。

因此,按照规则,对于您编写的每个Maven组件,我都会尝试使检查存储库的测试扩展某种MyBaseINtegrationTestClass,并将其放入其中

@ContextConfiguration(classes = {
        tutorial.www.baeldung.com.tutorial001jpa.separateDS.Tutorial001GenericEntityIntegrationTest.ConfigureJpa.class })

因此您只需要使用一种配置即可测试孔项目。

无论如何,希望这里给出的三元组可以帮助您。

一件好事,对于用于集成测试的Maven依赖项,这是我正在使用的东西:

<!-- Test Dependencies JPA REPOSITORY TESTS -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.hsqldb</groupId>
    <artifactId>hsqldb</artifactId>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>test</scope>
</dependency>

我之所以使用hsql和h2是因为我希望我的集成测试能够被调整为使用application-hsql或application-h2.properties。