Rozdělané fulltextové vyhledávání
This commit is contained in:
@@ -215,16 +215,20 @@
|
||||
|
||||
<!-- Hibernate -->
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-core</artifactId>
|
||||
<version>4.2.8.Final</version>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-core</artifactId>
|
||||
<version>4.2.8.Final</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
<version>4.3.0.Final</version>
|
||||
</dependency>
|
||||
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
<version>4.3.0.Final</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-search</artifactId>
|
||||
<version>4.4.6.Final</version>
|
||||
</dependency>
|
||||
|
||||
<!-- ZK -->
|
||||
<dependency>
|
||||
|
||||
@@ -11,6 +11,7 @@ import info.bukova.isspst.data.User;
|
||||
import info.bukova.isspst.reporting.Report;
|
||||
import info.bukova.isspst.reporting.ReportMapping;
|
||||
import info.bukova.isspst.reporting.ReportType;
|
||||
import info.bukova.isspst.services.FullTextService;
|
||||
import info.bukova.isspst.services.munits.MUnitService;
|
||||
import info.bukova.isspst.services.numberseries.NumberSeriesService;
|
||||
import info.bukova.isspst.services.requirement.RequirementTypeService;
|
||||
@@ -40,6 +41,7 @@ public class AppInitListener implements ServletContextListener {
|
||||
private NumberSeriesService nsService;
|
||||
private RequirementTypeService reqTypeService;
|
||||
private GlobalSettingsService gSettingsService;
|
||||
private FullTextService ftService;
|
||||
|
||||
@Override
|
||||
public void contextDestroyed(ServletContextEvent arg0) {
|
||||
@@ -59,6 +61,7 @@ public class AppInitListener implements ServletContextListener {
|
||||
nsService =ctx.getBean(NumberSeriesService.class);
|
||||
gSettingsService = ctx.getBean(GlobalSettingsService.class);
|
||||
reqTypeService = ctx.getBean(RequirementTypeService.class);
|
||||
ftService = ctx.getBean(FullTextService.class);
|
||||
|
||||
userService.grantAdmin();
|
||||
checkMUnits();
|
||||
@@ -69,11 +72,16 @@ public class AppInitListener implements ServletContextListener {
|
||||
this.checkNumberSeries();
|
||||
checkReqTypes();
|
||||
this.checkGlobalSettings();
|
||||
buildFulltext();
|
||||
userService.removeAccess();
|
||||
|
||||
loadModuleReports();
|
||||
}
|
||||
|
||||
private void buildFulltext() {
|
||||
ftService.reindex();
|
||||
}
|
||||
|
||||
private void checkMUnits()
|
||||
{
|
||||
List<MUnit> mUnits = mUnitsService.getAll();
|
||||
|
||||
@@ -4,11 +4,13 @@ import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import info.bukova.isspst.data.Order;
|
||||
import info.bukova.isspst.data.Permission;
|
||||
import info.bukova.isspst.data.PermissionType;
|
||||
import info.bukova.isspst.data.Requirement;
|
||||
import info.bukova.isspst.data.RequirementType;
|
||||
import info.bukova.isspst.data.Role;
|
||||
import info.bukova.isspst.data.TripBill;
|
||||
import info.bukova.isspst.data.TripRequirement;
|
||||
import info.bukova.isspst.reporting.Report;
|
||||
import info.bukova.isspst.reporting.ReportMapping;
|
||||
@@ -141,5 +143,7 @@ public class Constants {
|
||||
public final static Map<Class<?>, String> URL_MAP = Collections.unmodifiableMap(new HashMap<Class<?>, String>() {{
|
||||
put(Requirement.class, "/main/orders/");
|
||||
put(TripRequirement.class, "/main/trips/requirements/");
|
||||
put(Order.class, "/main/orders/created/");
|
||||
put(TripBill.class, "/main/trips/bill/");
|
||||
}} );
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ public class RequirementUrlResolver implements EntityUrlResolver {
|
||||
|
||||
Requirement req = (Requirement)entity;
|
||||
|
||||
if (req.getKind() == Constants.REQ_TYPE_MATERIAL) {
|
||||
if (req.getKind() != null && req.getKind() == Constants.REQ_TYPE_MATERIAL) {
|
||||
return defaultUrl + Constants.URL_MAP.get(req.getClass()) + "material/?select=" + String.valueOf(req.getId());
|
||||
} else {
|
||||
return defaultUrl + Constants.URL_MAP.get(req.getClass()) + "services/?select=" + String.valueOf(req.getId());
|
||||
|
||||
@@ -7,11 +7,18 @@ import java.util.List;
|
||||
|
||||
import javax.persistence.Embeddable;
|
||||
|
||||
import org.hibernate.search.annotations.Analyze;
|
||||
import org.hibernate.search.annotations.Field;
|
||||
import org.hibernate.search.annotations.Index;
|
||||
import org.hibernate.search.annotations.Indexed;
|
||||
|
||||
@Embeddable
|
||||
@Indexed
|
||||
public class AddressEmb
|
||||
{
|
||||
|
||||
private int id;
|
||||
@Field(index = Index.YES, analyze = Analyze.YES)
|
||||
private String company;
|
||||
private String department;
|
||||
private String contactName;
|
||||
|
||||
@@ -11,7 +11,11 @@ import javax.persistence.ManyToOne;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
import org.hibernate.search.annotations.Indexed;
|
||||
import org.hibernate.search.annotations.IndexedEmbedded;
|
||||
|
||||
@MappedSuperclass
|
||||
@Indexed
|
||||
public abstract class BaseData implements OwnedDataModel {
|
||||
|
||||
@Id
|
||||
@@ -24,9 +28,11 @@ public abstract class BaseData implements OwnedDataModel {
|
||||
private Date modified;
|
||||
@ManyToOne(fetch=FetchType.LAZY)
|
||||
@JoinColumn(name="OWNED_BY_ID")
|
||||
@IndexedEmbedded
|
||||
private User ownedBy;
|
||||
@ManyToOne(fetch=FetchType.LAZY)
|
||||
@JoinColumn(name="MODIFIED_BY_ID")
|
||||
@IndexedEmbedded
|
||||
private User modifiedBy;
|
||||
@Transient
|
||||
private boolean valid;
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
package info.bukova.isspst.data;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.annotations.Type;
|
||||
import org.hibernate.search.annotations.Analyze;
|
||||
import org.hibernate.search.annotations.Field;
|
||||
import org.hibernate.search.annotations.Index;
|
||||
import org.hibernate.search.annotations.Indexed;
|
||||
|
||||
@Entity
|
||||
@Table(name = "FILE_METAINFO")
|
||||
@Indexed
|
||||
public class FileMetainfo extends BaseData {
|
||||
|
||||
@Column(name = "FILE_NAME")
|
||||
private String fileName;
|
||||
@Column(name = "PATH_IN_FILESYSTEM")
|
||||
private String pathInFilesystem;
|
||||
@Column(name = "MODULE_ID")
|
||||
private String moduleId;
|
||||
@Column(name = "RECORD_ID")
|
||||
private int recordId;
|
||||
@Column(name = "CONTENT")
|
||||
@Type(type = "text")
|
||||
@Field(index = Index.YES, analyze = Analyze.YES)
|
||||
private String content;
|
||||
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public void setFileName(String fileName) {
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
public String getPathInFilesystem() {
|
||||
return pathInFilesystem;
|
||||
}
|
||||
|
||||
public void setPathInFilesystem(String pathInFilesystem) {
|
||||
this.pathInFilesystem = pathInFilesystem;
|
||||
}
|
||||
|
||||
public String getModuleId() {
|
||||
return moduleId;
|
||||
}
|
||||
|
||||
public void setModuleId(String moduleId) {
|
||||
this.moduleId = moduleId;
|
||||
}
|
||||
|
||||
public int getRecordId() {
|
||||
return recordId;
|
||||
}
|
||||
|
||||
public void setRecordId(int recordId) {
|
||||
this.recordId = recordId;
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,9 +16,15 @@ import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.annotations.LazyCollection;
|
||||
import org.hibernate.annotations.LazyCollectionOption;
|
||||
import org.hibernate.search.annotations.Analyze;
|
||||
import org.hibernate.search.annotations.Field;
|
||||
import org.hibernate.search.annotations.Index;
|
||||
import org.hibernate.search.annotations.Indexed;
|
||||
import org.hibernate.search.annotations.IndexedEmbedded;
|
||||
|
||||
@Entity
|
||||
@Table(name = "ORDERS")
|
||||
@Indexed
|
||||
public class Order extends BaseData implements Cloneable
|
||||
{
|
||||
|
||||
@@ -45,6 +51,7 @@ public class Order extends BaseData implements Cloneable
|
||||
@AttributeOverride(name = "street", column = @Column(name = "SUPPLIER_STREET")),
|
||||
@AttributeOverride(name = "web", column = @Column(name = "SUPPLIER_WEB")),
|
||||
@AttributeOverride(name = "zipCode", column = @Column(name = "SUPPLIER_ZIP_CODE")) })
|
||||
@IndexedEmbedded
|
||||
private AddressEmb suplier;
|
||||
|
||||
@Embedded
|
||||
@@ -95,10 +102,12 @@ public class Order extends BaseData implements Cloneable
|
||||
private String deliveryType;
|
||||
|
||||
@Column(name = "DESCRIPTION")
|
||||
@Field(index = Index.YES, analyze = Analyze.YES)
|
||||
private String description;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "order", orphanRemoval = true)
|
||||
@LazyCollection(LazyCollectionOption.TRUE)
|
||||
@IndexedEmbedded
|
||||
private List<OrderItem> items;
|
||||
|
||||
@Column(name = "TOTAL", precision = 15, scale = 4)
|
||||
|
||||
@@ -12,8 +12,14 @@ import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.search.annotations.Analyze;
|
||||
import org.hibernate.search.annotations.Field;
|
||||
import org.hibernate.search.annotations.Index;
|
||||
import org.hibernate.search.annotations.Indexed;
|
||||
|
||||
@Entity
|
||||
@Table(name = "ORDER_ITEM")
|
||||
@Indexed
|
||||
public class OrderItem
|
||||
{
|
||||
|
||||
@@ -26,9 +32,11 @@ public class OrderItem
|
||||
private String code;
|
||||
|
||||
@Column(name = "NAME")
|
||||
@Field(index = Index.YES, analyze = Analyze.YES)
|
||||
private String name;
|
||||
|
||||
@Column(name = "TEXTITEM")
|
||||
@Field(index = Index.YES, analyze = Analyze.YES)
|
||||
private String textItem;
|
||||
|
||||
@Column(name = "QUANTITY", precision = 15, scale = 4)
|
||||
@@ -44,6 +52,7 @@ public class OrderItem
|
||||
private BigDecimal total;
|
||||
|
||||
@Column(name = "DESCRIPTION")
|
||||
@Field(index = Index.YES, analyze = Analyze.YES)
|
||||
private String description;
|
||||
|
||||
@ManyToOne(fetch = FetchType.EAGER)
|
||||
|
||||
@@ -12,11 +12,16 @@ import javax.persistence.FetchType;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.search.annotations.Indexed;
|
||||
import org.hibernate.search.annotations.IndexedEmbedded;
|
||||
|
||||
@Entity
|
||||
@Table(name = "REQUIREMENT")
|
||||
@Indexed
|
||||
public class Requirement extends RequirementBase
|
||||
{
|
||||
@OneToMany(fetch = FetchType.LAZY, mappedBy = "requirement", cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
@IndexedEmbedded
|
||||
private List<RequirementItem> items;
|
||||
|
||||
@Column(name = "DELIVERYDATE")
|
||||
|
||||
@@ -17,8 +17,13 @@ import javax.persistence.OrderBy;
|
||||
|
||||
import org.hibernate.annotations.LazyCollection;
|
||||
import org.hibernate.annotations.LazyCollectionOption;
|
||||
import org.hibernate.search.annotations.Analyze;
|
||||
import org.hibernate.search.annotations.Field;
|
||||
import org.hibernate.search.annotations.Index;
|
||||
import org.hibernate.search.annotations.Indexed;
|
||||
|
||||
@MappedSuperclass
|
||||
@Indexed
|
||||
public class RequirementBase extends BaseData implements FilterableRequirement {
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@@ -33,6 +38,7 @@ public class RequirementBase extends BaseData implements FilterableRequirement {
|
||||
@Column(name = "REQ_DATE")
|
||||
private Date reqDate;
|
||||
@Column(name = "DESCRIPTION")
|
||||
@Field(index = Index.YES, analyze = Analyze.YES)
|
||||
private String description;
|
||||
@ManyToOne(fetch = FetchType.EAGER)
|
||||
@JoinColumn(name = "CENTRE_ID")
|
||||
|
||||
@@ -12,8 +12,15 @@ import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.search.annotations.Analyze;
|
||||
import org.hibernate.search.annotations.Field;
|
||||
import org.hibernate.search.annotations.Index;
|
||||
import org.hibernate.search.annotations.Indexed;
|
||||
import org.hibernate.search.annotations.IndexedEmbedded;
|
||||
|
||||
@Entity
|
||||
@Table(name = "REQUIREMENT_ITEMS")
|
||||
@Indexed
|
||||
public class RequirementItem
|
||||
{
|
||||
@Id
|
||||
@@ -33,9 +40,11 @@ public class RequirementItem
|
||||
private String code;
|
||||
|
||||
@Column(name = "NAME")
|
||||
@Field(index = Index.YES, analyze = Analyze.YES)
|
||||
private String name;
|
||||
|
||||
@Column(name = "TEXTITEM")
|
||||
@Field(index = Index.YES, analyze = Analyze.YES)
|
||||
private String textItem;
|
||||
|
||||
@Column(name = "QUANTITY", precision=15, scale=4)
|
||||
@@ -51,6 +60,7 @@ public class RequirementItem
|
||||
private BigDecimal total;
|
||||
|
||||
@Column(name = "DESCRIPTION")
|
||||
@Field(index = Index.YES, analyze = Analyze.YES)
|
||||
private String description;
|
||||
|
||||
@Column(name = "DELIVERED")
|
||||
|
||||
@@ -16,9 +16,12 @@ import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.annotations.LazyCollection;
|
||||
import org.hibernate.annotations.LazyCollectionOption;
|
||||
import org.hibernate.search.annotations.Indexed;
|
||||
import org.hibernate.search.annotations.IndexedEmbedded;
|
||||
|
||||
@Entity
|
||||
@Table(name = "TRIP_BILL")
|
||||
@Indexed
|
||||
public class TripBill extends BaseData {
|
||||
|
||||
@OneToOne(fetch = FetchType.EAGER)
|
||||
@@ -44,6 +47,10 @@ public class TripBill extends BaseData {
|
||||
private BigDecimal downPayment;
|
||||
@Column(name = "TOTAL", precision = 15, scale = 4)
|
||||
private BigDecimal total;
|
||||
@OneToMany
|
||||
@LazyCollection(LazyCollectionOption.TRUE)
|
||||
@IndexedEmbedded
|
||||
private List<FileMetainfo> attachedFiles;
|
||||
|
||||
public TripBill() {
|
||||
billItems = new ArrayList<TripBillItem>();
|
||||
@@ -121,4 +128,12 @@ public class TripBill extends BaseData {
|
||||
this.total = total;
|
||||
}
|
||||
|
||||
public List<FileMetainfo> getAttachedFiles() {
|
||||
return attachedFiles;
|
||||
}
|
||||
|
||||
public void setAttachedFiles(List<FileMetainfo> attachedFiles) {
|
||||
this.attachedFiles = attachedFiles;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,18 +11,27 @@ import javax.persistence.Entity;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.ManyToMany;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.annotations.LazyCollection;
|
||||
import org.hibernate.annotations.LazyCollectionOption;
|
||||
import org.hibernate.search.annotations.Analyze;
|
||||
import org.hibernate.search.annotations.Field;
|
||||
import org.hibernate.search.annotations.Index;
|
||||
import org.hibernate.search.annotations.Indexed;
|
||||
import org.hibernate.search.annotations.IndexedEmbedded;
|
||||
|
||||
@Entity
|
||||
@Table(name = "TRIPREQUIREMENT")
|
||||
@Indexed
|
||||
public class TripRequirement extends RequirementBase {
|
||||
|
||||
@Column(name = "TRIP_FROM")
|
||||
@Field(index = Index.YES, analyze = Analyze.YES)
|
||||
private String from;
|
||||
@Column(name = "TRIP_TO")
|
||||
@Field(index = Index.YES, analyze = Analyze.YES)
|
||||
private String to;
|
||||
@Column(name = "TRIP_DATE")
|
||||
private Date tripDate;
|
||||
@@ -40,6 +49,10 @@ public class TripRequirement extends RequirementBase {
|
||||
private Boolean requireDownPayment;
|
||||
@Column(name = "DOWN_PAYMENT", precision = 15, scale = 4)
|
||||
private BigDecimal downPayment;
|
||||
@OneToMany
|
||||
@LazyCollection(LazyCollectionOption.TRUE)
|
||||
@IndexedEmbedded
|
||||
private List<FileMetainfo> attachedFiles;
|
||||
|
||||
public TripRequirement() {
|
||||
this.setOwnedBy(new User());
|
||||
@@ -118,4 +131,12 @@ public class TripRequirement extends RequirementBase {
|
||||
this.downPayment = downPayment;
|
||||
}
|
||||
|
||||
public List<FileMetainfo> getAttachedFiles() {
|
||||
return attachedFiles;
|
||||
}
|
||||
|
||||
public void setAttachedFiles(List<FileMetainfo> attachedFiles) {
|
||||
this.attachedFiles = attachedFiles;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,10 +14,15 @@ import javax.persistence.JoinTable;
|
||||
import javax.persistence.ManyToMany;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.search.annotations.Analyze;
|
||||
import org.hibernate.search.annotations.Field;
|
||||
import org.hibernate.search.annotations.Index;
|
||||
import org.hibernate.search.annotations.Indexed;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
@Entity
|
||||
@Table(name="USER")
|
||||
@Indexed
|
||||
public class User extends Member implements UserDetails, DataModel {
|
||||
|
||||
/**
|
||||
@@ -32,8 +37,10 @@ public class User extends Member implements UserDetails, DataModel {
|
||||
@Column(name="ENABLED")
|
||||
private boolean enabled;
|
||||
@Column(name="FIRST_NAME")
|
||||
@Field(index = Index.YES, analyze = Analyze.YES)
|
||||
private String firstName;
|
||||
@Column(name="LAST_NAME")
|
||||
@Field(index = Index.YES, analyze = Analyze.YES)
|
||||
private String lastName;
|
||||
@Column(name="PERSONAL_NUMBER")
|
||||
private String personalNumber;
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package info.bukova.isspst.services;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface FullTextService {
|
||||
|
||||
public void reindex();
|
||||
public List<?> search(Class<?> entityClass, String[] fields, String word);
|
||||
public List<?> globalSearch(String word);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
package info.bukova.isspst.services;
|
||||
|
||||
import info.bukova.isspst.dao.QueryDao;
|
||||
import info.bukova.isspst.data.BaseData;
|
||||
import info.bukova.isspst.data.User;
|
||||
import info.bukova.isspst.sort.ReflectionTools;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.search.FullTextSession;
|
||||
import org.hibernate.search.Search;
|
||||
import org.hibernate.search.annotations.IndexedEmbedded;
|
||||
import org.hibernate.search.query.dsl.QueryBuilder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
public class FullTextServiceImpl implements FullTextService {
|
||||
|
||||
@Autowired
|
||||
private QueryDao queryDao;
|
||||
private List<Class<?>> classesForSearch;
|
||||
private Map<Class<?>, String[]> fields;
|
||||
private List<Class<?>> nestedClasses;
|
||||
|
||||
public FullTextServiceImpl() {
|
||||
nestedClasses = new ArrayList<Class<?>>();
|
||||
nestedClasses.add(User.class);
|
||||
nestedClasses.add(BaseData.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void reindex() {
|
||||
Logger logger = LoggerFactory.getLogger(FullTextServiceImpl.class);
|
||||
logger.info("Indexing database for fulltext search");
|
||||
FullTextSession ftSession = Search.getFullTextSession(queryDao.getSession());
|
||||
try {
|
||||
ftSession.createIndexer().startAndWait();
|
||||
} catch (InterruptedException e) {
|
||||
logger.error("Cannot index database");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public List<?> search(Class<?> entityClass, String[] fields, String word) {
|
||||
FullTextSession session = Search.getFullTextSession(queryDao.getSession());
|
||||
QueryBuilder qb = session.getSearchFactory().buildQueryBuilder().forEntity(entityClass).get();
|
||||
|
||||
Query luceneQuery = qb.keyword().onFields(fields).matching(word).createQuery();
|
||||
org.hibernate.Query hiberQuery = session.createFullTextQuery(luceneQuery, entityClass);
|
||||
|
||||
return hiberQuery.list();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public List<?> globalSearch(String word) {
|
||||
List<Object> result = new ArrayList<Object>();
|
||||
|
||||
for (Class<?> clazz : classesForSearch()) {
|
||||
result.addAll(search(clazz, fields.get(clazz), word));
|
||||
}
|
||||
|
||||
for (Object o : result) {
|
||||
BaseData data = (BaseData) o;
|
||||
Hibernate.initialize(data.getModifiedBy());
|
||||
Hibernate.initialize(data.getOwnedBy());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<Class<?>> classesForSearch() {
|
||||
if (classesForSearch != null) {
|
||||
return classesForSearch;
|
||||
}
|
||||
|
||||
classesForSearch = new ArrayList<Class<?>>();
|
||||
fields = new HashMap<Class<?>, String[]>();
|
||||
FullTextSession session = Search.getFullTextSession(queryDao.getSession());
|
||||
|
||||
for (Class<?> clazz : session.getSearchFactory().getIndexedTypes()) {
|
||||
if (nestedClasses.contains(clazz)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
classesForSearch.add(clazz);
|
||||
fields.put(clazz, fields(clazz, ""));
|
||||
}
|
||||
|
||||
return classesForSearch;
|
||||
}
|
||||
|
||||
private String[] fields(Class<?> clazz, String prefix) {
|
||||
List<String> res = new ArrayList<String>();
|
||||
|
||||
for (Field field : ReflectionTools.getFields(clazz)) {
|
||||
for (Annotation a : field.getDeclaredAnnotations()) {
|
||||
if (a instanceof org.hibernate.search.annotations.Field) {
|
||||
res.add(prefix + field.getName());
|
||||
}
|
||||
|
||||
if (a instanceof IndexedEmbedded) {
|
||||
Class<?> fieldClass;
|
||||
|
||||
fieldClass = field.getType();
|
||||
if (fieldClass.isAssignableFrom(List.class)) {
|
||||
ParameterizedType type = (ParameterizedType) field.getGenericType();
|
||||
Type[] types = type.getActualTypeArguments();
|
||||
if (types.length == 1) {
|
||||
fieldClass = (Class<?>)types[0];
|
||||
}
|
||||
}
|
||||
|
||||
classesForSearch.remove(fieldClass);
|
||||
fields.remove(fieldClass);
|
||||
nestedClasses.add(fieldClass);
|
||||
|
||||
String nestedPrefix = prefix + field.getName() + ".";
|
||||
res.addAll(Arrays.asList(fields(fieldClass, nestedPrefix)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String resArray[] = new String[res.size()];
|
||||
resArray = res.toArray(resArray);
|
||||
return resArray;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,8 +4,10 @@ import java.beans.BeanInfo;
|
||||
import java.beans.IntrospectionException;
|
||||
import java.beans.Introspector;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class ReflectionTools {
|
||||
@@ -78,4 +80,23 @@ public class ReflectionTools {
|
||||
|
||||
return getEntityFields(entity.getClass());
|
||||
}
|
||||
|
||||
public static List<Field> getFields(Object entity) {
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return getFields(entity.getClass());
|
||||
}
|
||||
|
||||
public static List<Field> getFields(Class<?> clazz) {
|
||||
List<Field> ret = new ArrayList<Field>();
|
||||
|
||||
ret.addAll(Arrays.asList(clazz.getDeclaredFields()));
|
||||
if (!clazz.getSuperclass().equals(Object.class)) {
|
||||
ret.addAll(getFields(clazz.getSuperclass()));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package info.bukova.isspst.ui.search;
|
||||
|
||||
import info.bukova.isspst.EntityUrlResolver;
|
||||
import info.bukova.isspst.data.BaseData;
|
||||
|
||||
public abstract class AbstractResultTransformer implements ResultTransformer {
|
||||
|
||||
protected EntityUrlResolver urlResolver;
|
||||
|
||||
@Override
|
||||
public SearchResult transformObject(Object object) {
|
||||
BaseData data = (BaseData)object;
|
||||
SearchResult result = new SearchResult();
|
||||
|
||||
result.setCreated(data.getCreated());
|
||||
result.setModified(data.getModified());
|
||||
result.setOwnedBy(data.getOwnedBy());
|
||||
result.setModifiedBy(data.getModifiedBy());
|
||||
|
||||
if (urlResolver != null) {
|
||||
result.setUrl(urlResolver.entityUrl(data));
|
||||
}
|
||||
|
||||
|
||||
transform(object, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected abstract void transform(Object object, SearchResult result);
|
||||
|
||||
@Override
|
||||
public void setUrlResolver(EntityUrlResolver resolver) {
|
||||
this.urlResolver = resolver;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package info.bukova.isspst.ui.search;
|
||||
|
||||
|
||||
public class CommonResultTransformer extends AbstractResultTransformer implements ResultTransformer {
|
||||
|
||||
@Override
|
||||
protected void transform(Object object, SearchResult result) {
|
||||
result.setRecordName("Neznámá entita");
|
||||
result.setDescription(object.toString());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package info.bukova.isspst.ui.search;
|
||||
|
||||
import info.bukova.isspst.data.Order;
|
||||
|
||||
public class OrderResultTransformer extends AbstractResultTransformer implements ResultTransformer {
|
||||
|
||||
@Override
|
||||
protected void transform(Object object, SearchResult result) {
|
||||
Order order = (Order)object;
|
||||
result.setRecordName("Objednávka: " + order.getNumser());
|
||||
result.setDescription(order.getDescription() + ", dodavatel: " + order.getSuplier().getCompany());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package info.bukova.isspst.ui.search;
|
||||
|
||||
import info.bukova.isspst.data.Requirement;
|
||||
|
||||
public class RequirementResultTransformer extends AbstractResultTransformer implements ResultTransformer {
|
||||
|
||||
@Override
|
||||
protected void transform(Object object, SearchResult result) {
|
||||
Requirement req = (Requirement)object;
|
||||
result.setRecordName("Požadavek na nákup/službu: " + req.getNumser());
|
||||
result.setDescription(req.getDescription());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package info.bukova.isspst.ui.search;
|
||||
|
||||
import info.bukova.isspst.EntityUrlResolver;
|
||||
|
||||
public interface ResultTransformer {
|
||||
|
||||
public SearchResult transformObject(Object object);
|
||||
public void setUrlResolver(EntityUrlResolver resolver);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package info.bukova.isspst.ui.search;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.zkoss.bind.annotation.Command;
|
||||
import org.zkoss.bind.annotation.NotifyChange;
|
||||
import org.zkoss.zk.ui.select.annotation.WireVariable;
|
||||
|
||||
import info.bukova.isspst.UrlResolverHolder;
|
||||
import info.bukova.isspst.data.BaseData;
|
||||
import info.bukova.isspst.data.Requirement;
|
||||
import info.bukova.isspst.data.TripRequirement;
|
||||
import info.bukova.isspst.services.FullTextService;
|
||||
|
||||
public class SearchForm {
|
||||
|
||||
@WireVariable
|
||||
private FullTextService fulltextService;
|
||||
@WireVariable
|
||||
private UrlResolverHolder urlResolverHolder;
|
||||
private List<SearchResult> results;
|
||||
|
||||
private String keyWord;
|
||||
|
||||
public void init() {
|
||||
|
||||
}
|
||||
|
||||
@Command
|
||||
@NotifyChange("results")
|
||||
public void doSearch() {
|
||||
if (keyWord == null || keyWord.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//String[] fields = {"items.textItem", "description"};
|
||||
List<?> result = fulltextService.globalSearch(keyWord);
|
||||
//List<?> result = fulltextService.search(Requirement.class, fields, keyWord);
|
||||
|
||||
SearchListTransformer srt = new SearchListTransformer(urlResolverHolder);
|
||||
results = srt.transform(result);
|
||||
|
||||
System.out.println(result.size());
|
||||
}
|
||||
|
||||
public String getKeyWord() {
|
||||
return keyWord;
|
||||
}
|
||||
|
||||
public void setKeyWord(String keyWord) {
|
||||
this.keyWord = keyWord;
|
||||
}
|
||||
|
||||
public List<SearchResult> getResults() {
|
||||
return results;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package info.bukova.isspst.ui.search;
|
||||
|
||||
import info.bukova.isspst.UrlResolverHolder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class SearchListTransformer {
|
||||
|
||||
private UrlResolverHolder urlResolverHolder;
|
||||
|
||||
public SearchListTransformer() {
|
||||
urlResolverHolder = null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public SearchListTransformer(UrlResolverHolder urlResolverHolder) {
|
||||
super();
|
||||
this.urlResolverHolder = urlResolverHolder;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public List<SearchResult> transform(List<?> source) {
|
||||
List<SearchResult> ret = new ArrayList<SearchResult>();
|
||||
|
||||
for (int i = 0; i < source.size(); i++) {
|
||||
ResultTransformer transformer = TransformerFactory.transformerFor(source.get(i));
|
||||
if (urlResolverHolder != null) {
|
||||
transformer.setUrlResolver(urlResolverHolder.resolverFor(source.get(i).getClass()));
|
||||
}
|
||||
ret.add(transformer.transformObject(source.get(i)));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package info.bukova.isspst.ui.search;
|
||||
|
||||
import info.bukova.isspst.data.User;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class SearchResult {
|
||||
|
||||
private String recordName;
|
||||
private String description;
|
||||
private String url;
|
||||
private Date created;
|
||||
private Date modified;
|
||||
private User ownedBy;
|
||||
private User modifiedBy;
|
||||
|
||||
public String getRecordName() {
|
||||
return recordName;
|
||||
}
|
||||
|
||||
public void setRecordName(String recordName) {
|
||||
this.recordName = recordName;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public Date getCreated() {
|
||||
return created;
|
||||
}
|
||||
|
||||
public void setCreated(Date created) {
|
||||
this.created = created;
|
||||
}
|
||||
|
||||
public Date getModified() {
|
||||
return modified;
|
||||
}
|
||||
|
||||
public void setModified(Date modified) {
|
||||
this.modified = modified;
|
||||
}
|
||||
|
||||
public User getOwnedBy() {
|
||||
return ownedBy;
|
||||
}
|
||||
|
||||
public void setOwnedBy(User ownedBy) {
|
||||
this.ownedBy = ownedBy;
|
||||
}
|
||||
|
||||
public User getModifiedBy() {
|
||||
return modifiedBy;
|
||||
}
|
||||
|
||||
public void setModifiedBy(User modifiedBy) {
|
||||
this.modifiedBy = modifiedBy;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package info.bukova.isspst.ui.search;
|
||||
|
||||
import info.bukova.isspst.data.Order;
|
||||
import info.bukova.isspst.data.Requirement;
|
||||
import info.bukova.isspst.data.TripBill;
|
||||
import info.bukova.isspst.data.TripRequirement;
|
||||
|
||||
public class TransformerFactory {
|
||||
|
||||
public static ResultTransformer transformerFor(Object object) {
|
||||
if (object instanceof TripBill) {
|
||||
return new TripBillTransformer();
|
||||
}
|
||||
if (object instanceof TripRequirement) {
|
||||
return new TripRequirementTransformer();
|
||||
}
|
||||
if (object instanceof Requirement) {
|
||||
return new RequirementResultTransformer();
|
||||
}
|
||||
if (object instanceof Order) {
|
||||
return new OrderResultTransformer();
|
||||
}
|
||||
|
||||
return new CommonResultTransformer();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package info.bukova.isspst.ui.search;
|
||||
|
||||
import info.bukova.isspst.data.TripBill;
|
||||
|
||||
public class TripBillTransformer extends AbstractResultTransformer implements ResultTransformer {
|
||||
|
||||
@Override
|
||||
protected void transform(Object object, SearchResult result) {
|
||||
TripBill tb = (TripBill)object;
|
||||
result.setRecordName("Vyúčtování služební cesty: " + tb.getRequirement().getNumser());
|
||||
result.setDescription("Z " + tb.getRequirement().getFrom() + " do " + tb.getRequirement().getTo() + " - " + tb.getRequirement().getDescription());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package info.bukova.isspst.ui.search;
|
||||
|
||||
import info.bukova.isspst.data.TripRequirement;
|
||||
|
||||
public class TripRequirementTransformer extends AbstractResultTransformer implements ResultTransformer {
|
||||
|
||||
@Override
|
||||
protected void transform(Object object, SearchResult result) {
|
||||
TripRequirement tr = (TripRequirement)object;
|
||||
result.setRecordName("Žádost o služební cestu: " + tr.getNumser());
|
||||
result.setDescription("Z " + tr.getFrom() + " do " + tr.getTo() + " - " + tr.getDescription());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -32,5 +32,6 @@
|
||||
<mapping class="info.bukova.isspst.data.OrderItem"></mapping>
|
||||
<mapping class="info.bukova.isspst.data.Invoicing"></mapping>
|
||||
<mapping class="info.bukova.isspst.data.InvoicingItem"></mapping>
|
||||
<mapping class="info.bukova.isspst.data.FileMetainfo"></mapping>
|
||||
</session-factory>
|
||||
</hibernate-configuration>
|
||||
@@ -52,8 +52,11 @@
|
||||
<property name="hibernateProperties">
|
||||
<props>
|
||||
<prop key="hibernate.dialect">${jdbc.dialect}</prop>
|
||||
<prop key="hibernate.show_sql">false</prop>
|
||||
<prop key="hibernate.show_sql">true</prop>
|
||||
<prop key="hibernate.hbm2ddl.auto">update</prop>
|
||||
<prop key="hibernate.search.default.directory_provider">filesystem</prop>
|
||||
<prop key="hibernate.search.default.indexBase">/home/pepa/Dokumenty/dev/lucene</prop>
|
||||
<prop key="hibernate.search.analyzer">org.apache.lucene.analysis.cz.CzechAnalyzer</prop>
|
||||
<!-- <prop key="hibernate.enable_lazy_load_no_trans">true</prop> -->
|
||||
</props>
|
||||
</property>
|
||||
@@ -423,4 +426,6 @@
|
||||
<property name="validator" ref="validator"/>
|
||||
</bean>
|
||||
|
||||
<bean id="fulltextService" class="info.bukova.isspst.services.FullTextServiceImpl"/>
|
||||
|
||||
</beans>
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
<?page title="Search" contentType="text/html;charset=UTF-8"?>
|
||||
<zk>
|
||||
<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>
|
||||
|
||||
<window title="Search" border="normal" closable="true"
|
||||
apply="org.zkoss.bind.BindComposer"
|
||||
viewModel="@id('vm') @init('info.bukova.isspst.ui.search.SearchForm')"
|
||||
vflex="1">
|
||||
|
||||
<vbox width="100%"
|
||||
vflex="1">
|
||||
<hbox>
|
||||
<textbox value="@bind(vm.keyWord)" />
|
||||
<button label="Hledat" onClick="@command('doSearch')" />
|
||||
</hbox>
|
||||
<panel hflex="1" vflex="1">
|
||||
<panelchildren style="overflow:auto;">
|
||||
<vbox children="@load(vm.results)" width="100%">
|
||||
<template name="children">
|
||||
<vbox width="100%">
|
||||
<separator bar="true" width="100%"/>
|
||||
<label value="@load(each.recordName)" style="font-weight: bold; font-size:14px;"/>
|
||||
<label value="@load(each.description)"/>
|
||||
<hbox>
|
||||
<label value="Vytvořeno: "/>
|
||||
<label value="@load(each.created)"/>
|
||||
</hbox>
|
||||
<hbox>
|
||||
<label value="Vytvořil: "/>
|
||||
<label value="@load(each.ownedBy)"/>
|
||||
</hbox>
|
||||
<hbox>
|
||||
<label value="Změněno: "/>
|
||||
<label value="@load(each.modified)"/>
|
||||
</hbox>
|
||||
<hbox>
|
||||
<label value="Změnil: "/>
|
||||
<label value="@load(each.modifiedBy)"/>
|
||||
</hbox>
|
||||
<a href="@load(each.url)" label="@load(each.url)"/>
|
||||
</vbox>
|
||||
</template>
|
||||
</vbox>
|
||||
</panelchildren>
|
||||
</panel>
|
||||
</vbox>
|
||||
|
||||
</window>
|
||||
</zk>
|
||||
Reference in New Issue
Block a user