当使用基于tomcat

时间:2019-01-11 19:12:24

标签: java spring hibernate hibernate-search

我有以下问题:我正在使用Hibernate,MySql5.5,Java 7和Apache Tomcat 7.0开发基于Spring的信息系统。我必须满足的要求指定了使用查找程序来查找任务。必须使用keywordmax datemin datemax pricemin pricecategory name和{ {1}}。 warranty title必须出现在以下任何任务属性中:keyword(字母数字标识符),tickerdescription。价格范围适用于任务属性address,日期范围适用于任务的pricestart date。当然,end datecategory name都适用于与某个任务相关的任务

我已经使用休眠搜索开发了该查找器的实现,当我为查找器执行jUnit测试时,它实际上会返回正确的任务列表。当我尝试使用使用Tomcat本地部署的信息系统测试此查找器时,就会出现问题。即使使用与jUnit测试中相同的参数,结果仍然是一个空列表。另外,每当我执行代表任务搜索的编辑表单的提交时,Eclipse控制台都会引发以下警告消息:warranty title。我不知道先前的警告如何影响我的问题。

Here you have the UML domain model of the entities previously specified


任务

[http-bio-8080-exec-9] WARN  org.hibernate.jpa.internal.EntityManagerFactoryRegistry  - HHH00043
6: Entity manager factory name (Acme-HandyWorker) is already registered.  If entity manager will be clustered or passiva
ted, specify a unique value for property 'hibernate.ejb.entitymanager_factory_name'

保修

@Indexed
@Entity
@Access(AccessType.PROPERTY)
public class Task extends DomainEntity {

private String ticker;
private Date publicationMoment;
private String description;
private String address;
private double maxPrice;
private Date startDate;
private Date endDate;
private Warranty warranty;
private Category category;
private Collection<Complaint> complaints;
private Customer customer;
private Collection<Application> applications;

@Field
@NotBlank
@Column(unique = true)
@Pattern(regexp = "^[0-9]{6}-[A-Z0-9]{6}$")
public String getTicker() {
return this.ticker;
}

public void setTicker(final String ticker) {
this.ticker = ticker;
}

@Past
@NotNull
@Temporal(TemporalType.TIMESTAMP)
@DateTimeFormat(pattern = "dd/MM/yyyy HH:mm")
public Date getPublicationMoment() {
return this.publicationMoment;
}

public void setPublicationMoment(final Date publicationMoment) {
this.publicationMoment = publicationMoment;
}

@Field
@NotBlank
public String getDescription() {
return this.description;
}

public void setDescription(final String description) {
this.description = description;
}

@Field
@NotBlank
public String getAddress() {
return this.address;
}

public void setAddress(final String address) {
this.address = address;
}

@Min(0)
@Digits(integer = 99, fraction = 2)
@Field
@NumericField
public double getMaxPrice() {
return this.maxPrice;
}

public void setMaxPrice(final double maxPrice) {
this.maxPrice = maxPrice;
}

@Past
@NotNull
@Temporal(TemporalType.DATE)
@DateTimeFormat(pattern = "dd/MM/yyyy")
@Field
public Date getStartDate() {
return this.startDate;
}

public void setStartDate(final Date startDate) {
this.startDate = startDate;
}

@NotNull
@Temporal(TemporalType.DATE)
@DateTimeFormat(pattern = "dd/MM/yyyy")
@Field
public Date getEndDate() {
return this.endDate;
}

public void setEndDate(final Date endDate) {
this.endDate = endDate;
}

@Valid
@ManyToOne(optional = false)
@IndexedEmbedded
public Warranty getWarranty() {
return this.warranty;
}

public void setWarranty(final Warranty warranty) {
this.warranty = warranty;
}

@Valid
@ManyToOne(optional = false)
@IndexedEmbedded
public Category getCategory() {
return this.category;
}

public void setCategory(final Category category) {
this.category = category;
}

@NotNull
@OneToMany
public Collection<Complaint> getComplaints() {
return this.complaints;
}

public void setComplaints(final Collection<Complaint> complaints) {
this.complaints = complaints;
}

@Valid
@ManyToOne(optional = false)
public Customer getCustomer() {
return this.customer;
}

public void setCustomer(final Customer customer) {
this.customer = customer;
}

@NotNull
@OneToMany(mappedBy = "task")
public Collection<Application> getApplications() {
return this.applications;
}

public void setApplications(final Collection<Application> applications) {
this.applications = applications;
}

}

类别

@Entity
@Access(AccessType.PROPERTY)
public class Warranty extends DomainEntity {

private String              title;
private Collection<String>  terms;
private Collection<String>  laws;
private String              mode;


@NotBlank
@Field
public String getTitle() {
    return this.title;
}

public void setTitle(final String title) {
    this.title = title;
}

@NotEmpty
@ElementCollection
public Collection<String> getTerms() {
    return this.terms;
}

public void setTerms(final Collection<String> terms) {
    this.terms = terms;
}

@NotEmpty
@ElementCollection
public Collection<String> getLaws() {
    return this.laws;
}

public void setLaws(final Collection<String> laws) {
    this.laws = laws;
}

@NotBlank
@Pattern(regexp = "^(DRAFT|FINAL)$")
public String getMode() {
    return this.mode;
}

public void setMode(final String mode) {
    this.mode = mode;
}

}

Finder

@Entity
@Access(AccessType.PROPERTY)
public class Category extends DomainEntity {

private String      name;
private String      nameEs;
private Category    father;


@NotBlank
@Field
public String getName() {
    return this.name;
}

public void setName(final String name) {
    this.name = name;
}

@NotBlank
@Field
public String getNameEs() {
    return this.nameEs;
}

public void setNameEs(final String nameEs) {
    this.nameEs = nameEs;
}

@Valid
@ManyToOne(optional = true)
public Category getFather() {
    return this.father;
}

public void setFather(final Category father) {
    this.father = father;
}

}

pom.xml

@Entity
@Access(AccessType.PROPERTY)
public class Finder extends DomainEntity {

private String keyWord;
private Double minPrice;
private Double maxPrice;
private Date minDate;
private Date maxDate;
private String categoryName;
private String warrantyTitle;
private Collection<Task> tasks;
private Date moment;

@NotNull
public String getKeyWord() {
return this.keyWord;
}

public void setKeyWord(final String keyWord) {
this.keyWord = keyWord;
}

@Min(0)
@Digits(integer = 99, fraction = 2)
public Double getMinPrice() {
return this.minPrice;
}

public void setMinPrice(final Double minPrice) {
this.minPrice = minPrice;
}

@Min(0)
@Digits(integer = 99, fraction = 2)
public Double getMaxPrice() {
return this.maxPrice;
}

public void setMaxPrice(final Double maxPrice) {
this.maxPrice = maxPrice;
}

@Temporal(TemporalType.DATE)
@DateTimeFormat(pattern = "dd/MM/yyyy")
public Date getMinDate() {
return this.minDate;
}

public void setMinDate(final Date minDate) {
this.minDate = minDate;
}

@Temporal(TemporalType.DATE)
@DateTimeFormat(pattern = "dd/MM/yyyy")
public Date getMaxDate() {
return this.maxDate;
}

public void setMaxDate(final Date maxDate) {
this.maxDate = maxDate;
}

@NotNull
public String getCategoryName() {
return this.categoryName;
}

public void setCategoryName(final String categoryName) {
this.categoryName = categoryName;
}

@NotNull
public String getWarrantyTitle() {
return this.warrantyTitle;
}

public void setWarrantyTitle(final String warrantyTitle) {
this.warrantyTitle = warrantyTitle;
}

@NotNull
@ManyToMany
public Collection<Task> getTasks() {
return this.tasks;
}

public void setTasks(final Collection<Task> tasks) {
this.tasks = tasks;
}

@NotNull
@Temporal(TemporalType.TIMESTAMP)
@DateTimeFormat(pattern = "dd/MM/yyyy")
public Date getMoment() {
return this.moment;
}

public void setMoment(final Date moment) {
this.moment = moment;
}

}

persistence.xml

<!-- Hibernate -->

    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
        <version>4.3.0.Final</version>
    </dependency>

    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>4.3.1.Final</version>
    </dependency>

    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-c3p0</artifactId>
        <version>4.2.3.Final</version>
    </dependency>

    <!-- Hibernate Full-text search -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-search</artifactId>
        <version>4.5.3.Final</version>
    </dependency>

过滤任务的实现

<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">

<persistence-unit name="Acme-HandyWorker">
    <properties>
        <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
        <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/Acme-HandyWorker" />
        <property name="javax.persistence.jdbc.user" value="acme-manager" />
        <property name="javax.persistence.jdbc.password" value="ACME-M@n@ger-6874" />

        <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
        <property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy" />

        <!-- Hibernate Full-text search -->
        <property name="hibernate.search.default.directory_provider" value="org.hibernate.search.store.impl.FSDirectoryProvider"/>
        <property name="hibernate.search.default.indexBase" value="var/lucene/indexes"/>
    </properties>

</persistence-unit>

jUnit测试

public List<Task> filterTasks() {
    final Finder f = this.finderService.findOne();

    final String keyword = f.getKeyWord().toLowerCase();
    final double minPrice = f.getMinPrice();
    final double maxPrice = f.getMaxPrice();
    final Date minDate = f.getMinDate();

    final Date maxDate = f.getMaxDate();
    final String category = f.getCategoryName().toLowerCase();
    final String warranty = f.getWarrantyTitle().toLowerCase();

    final ConfigurationParameters conf = this.configurationParametersService.find();
    final int max = conf.getMaxResults();

    final EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("Acme-HandyWorker");
    final EntityManager em = entityManagerFactory.createEntityManager();
    final FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(em);

    em.getTransaction().begin();

    final QueryBuilder qb = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity(Task.class).get();

    final org.apache.lucene.search.Query checkKeyword = qb.bool().should(qb.keyword().wildcard().onField("ticker").matching("*" + keyword + "*").createQuery())
        .should(qb.keyword().wildcard().onField("description").matching("*" + keyword + "*").createQuery()).should(qb.keyword().wildcard().onField("address").matching("*" + keyword + "*").createQuery()).createQuery();

    final org.apache.lucene.search.Query checkCategory = qb.bool().should(qb.keyword().wildcard().onField("category.name").matching("*" + category + "*").createQuery())
        .should(qb.keyword().wildcard().onField("category.nameEs").matching("*" + category + "*").createQuery()).createQuery();

    final org.apache.lucene.search.Query query = qb.bool().must(checkKeyword).must(qb.range().onField("maxPrice").from(minPrice).to(maxPrice).createQuery()).must(qb.range().onField("startDate").above(minDate).createQuery())
        .must(qb.range().onField("endDate").below(maxDate).createQuery()).must(checkCategory).must(qb.keyword().wildcard().onField("warranty.title").matching("*" + warranty + "*").createQuery()).createQuery();

    final FullTextEntityManager fullTextSession = Search.getFullTextEntityManager(fullTextEntityManager);
    final org.hibernate.search.jpa.FullTextQuery fullTextQuery = fullTextSession.createFullTextQuery(query);

    fullTextQuery.setMaxResults(max);

    // execute search
    final List result = fullTextQuery.getResultList();

    em.getTransaction().commit();
    em.close();

    return result;
}

在控制台中打印出sysout:

    @Test
public void testSave() {
    super.authenticate("handyworker40");

    final Finder f = this.finderService.findOne();
    f.setMaxPrice(120.);
    final String maxDateInString = "20/11/2018";
    final Date maxDate = this.defaultDate(maxDateInString);
    final String minDateInString = "06/04/2018";
    final Date minDate = this.defaultDate(minDateInString);
    f.setMaxDate(maxDate);
    f.setMinDate(minDate);

    final Finder saved = this.finderService.save(f);

    final Collection<Finder> fs = this.finderService.findAll();
    System.out.println(saved.getTasks());

    Assert.isTrue(fs.contains(saved));

}
private Date defaultDate(final String dateInString) {
    final SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy");
    Date res = new Date();
    try {
        res = formatter.parse(dateInString);
    } catch (final ParseException e) {
        throw new RuntimeException(e);
    }

    return res;
}

取景器控制器

[domain.Task{id=3804, version=0}, domain.Task{id=3807, version=0}, domain.Task{id=3813, version=0}, domain.Task{id=3818,
 version=0}, domain.Task{id=3819, version=0}, domain.Task{id=3826, version=0}, domain.Task{id=3827, version=0}]

Finder服务保存方法

@RequestMapping(value = "/edit", method = RequestMethod.GET)
public ModelAndView edit() {
    ModelAndView result;
    Finder finder;
    final boolean clear;

    finder = this.finderService.findOne();

    clear = this.finderService.clearCache(finder);

    if (clear) {
        final Collection<Task> empty = new ArrayList<>();
        finder.setTasks(empty);
    }

    result = this.createEditModelAndView(finder);

    return result;
}

@RequestMapping(value = "/edit", method = RequestMethod.POST, params = "find")
public ModelAndView save(@Valid final Finder finder, final BindingResult binding) {
    ModelAndView result;

    if (binding.hasErrors())
        result = this.createEditModelAndView(finder);
    else
        try {
            this.finderService.save(finder);
            result = new ModelAndView("redirect:display.do");
        } catch (final Throwable oops) {
            result = this.createEditModelAndView(finder, "finder.commit.error");
        }

    return result;
}

protected ModelAndView createEditModelAndView(final Finder finder) {
    ModelAndView result;

    result = this.createEditModelAndView(finder, null);

    return result;
}

protected ModelAndView createEditModelAndView(final Finder finder, final String messageCode) {
    final ModelAndView result;
    Collection<Warranty> warranties;
    Collection<Category> categories;
    double maxPrice;
    String lang;

    lang = LocaleContextHolder.getLocale().getLanguage();

    warranties = this.warrantyService.findAll();
    categories = this.categoryService.findAll();
    maxPrice = this.taskService.findMaxPrice();

    result = new ModelAndView("finder/edit");
    result.addObject("finder", finder);
    result.addObject("warranties", warranties);
    result.addObject("categories", categories);
    result.addObject("maxPrice", maxPrice);
    result.addObject("lang", lang);

    result.addObject("message", messageCode);

    return result;
}

edit.jsp

    public Finder save(final Finder f) {
    Assert.notNull(f);

    final HandyWorker principal = this.handyWorkerService.findByPrincipal();
    final Date moment = new Date(System.currentTimeMillis());
    f.setMoment(moment);

    if (f.getMaxDate().equals(null)) {
        final String maxDateInString = "31/12/9999";
        final Date maxDate = this.defaultDate(maxDateInString);
        f.setMaxDate(maxDate);
    } else if (f.getMinDate().equals(null)) {
        final String minDateInString = "31/12/999";
        final Date minDate = this.defaultDate(minDateInString);
        f.setMinDate(minDate);
    } else if (f.getMaxPrice().equals(null)) {
        final double maxPrice = this.taskService.findMaxPrice();
        f.setMaxPrice(maxPrice);
    } else if (f.getMinPrice().equals(null))
        f.setMinPrice(0.);

    final Finder saved = this.finderRepository.save(f);

    if (f.getId() == 0) {
        principal.setFinder(saved);
        this.handyWorkerService.save(principal);
    } else
        Assert.isTrue(saved.equals(f));

    final Collection<Task> filteredTasks = this.taskService.filterTasks();
    saved.setTasks(filteredTasks);

    return this.finderRepository.save(saved);
}

Here you can see the editing view with the same parameters as in the jUNit test

这是显示结果视图中的结果:result

1 个答案:

答案 0 :(得分:0)

首先,一个警告:在运行时执行以下代码确实是可疑的。

final EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("Acme-HandyWorker");

每次执行filterTasks()方法时,您正在创建一个实体管理器工厂。但是,实体管理器工厂旨在成为一个单例,可以在每个线程的所有应用程序中重复使用。对于给定的持久性单元,通常不应有多个实体管理器工厂实例。

我鼓励您使用为您管理实体管理器工厂和实体管理器的框架。 Spring Boot是其中的一个,WildFly是另一个,但是我敢肯定,您会发现几乎任何框架都可以为您做到这一点。

如果您真的想自己处理它,那么至少在启动应用程序时创建实体管理器工厂,将其存储在某个位置以供运行时方法(例如filterTasks())检索,并确保将其关闭当您的应用程序关闭时。

关于您的问题

最可能的解释是您没有索引数据。在测试中,您将数据持久保存到数据库中,因此Hibernate Search将即时获取写入事件和索引。在生产中,数据(据我了解)已经存在,因此Hibernate Search没有机会对其进行索引。

要索引数据库中已有的内容,请查看mass indexing;基本上,您在首次启动应用程序时将需要运行以下操作:

EntityManager em = entityManagerFactory.createEntityManager();
FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(em);
fullTextEntityManager.createIndexer().startAndWait();

质量索引器有很多选择,请参考文档以使用最适合您的选择。

旁注

仅在您构建新应用程序的情况下,我想提到的是,您使用的Hibernate ORM和Hibernate Search版本是古老的,因此您很可能会遇到已在较新版本中修复的错误。在新的应用程序中,您可能应该使用更新的版本。尽管我了解您可能没有选择,尤其是如果它是旧版应用程序。

如果您坚持使用Java 7,我建议您升级到Hibernate ORM 5.1和Hibernate Search 5.6。理想情况下,您应该考虑升级到Java 8,ORM 5.4和Search 5.11。迁移可能需要对您的应用程序进行更改,但是hibernate.org,here for Hibernate Search和[这里是Hibernate ORM])(http://hibernate.org/orm/documentation/5.4/)上有可用的迁移指南(对于ORM,您必须选择一个版本(使用右上角的选择框)。