springboot,jpa 添加全文索引
时间:2019-04-04 13:00:18
收藏:0
阅读:174
因项目中需要对表的一些列进行全文索引,但是jpa是不带全文索引创建的功能,所以自己写了一个创建全文索引注解
来自动创建全文索引,需要配合spring 或 springboot使用,一定要spring扫描到如下类:
ApplicationUtil.java
ClassScaner.java
FulltextDelegator.java
1.获取spring环境的上下文
import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.annotation.Configuration; /** * 获取上下文 * @project order * @fileName ApplicationUtil.java * @Description * @author light-zhang * @date 2019年4月3日 * @version 1.0.0 */ @Configuration public class ApplicationUtil implements ApplicationContextAware { private static ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { ApplicationUtil.applicationContext = applicationContext; } public static ApplicationContext getApplicationContext() { return applicationContext; } }
2.扫描指定包下面的所有类信息
import java.io.IOException; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.context.ResourceLoaderAware; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternUtils; import org.springframework.core.type.classreading.CachingMetadataReaderFactory; import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.core.type.filter.TypeFilter; import org.springframework.util.StringUtils; import org.springframework.util.SystemPropertyUtils; /** * 扫描指定的包下面的类信息 * * @project order * @fileName ClassScaner.java * @Description * @author light-zhang * @date 2019年4月2日 * @version 1.0.0 */ @Configuration public class ClassScaner implements ResourceLoaderAware { private static final String FULLTEXT_SACN_PACKAGE_PATH = "fulltext.scan.package"; private final List<TypeFilter> includeFilters = new LinkedList<TypeFilter>(); private final List<TypeFilter> excludeFilters = new LinkedList<TypeFilter>(); private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory( this.resourcePatternResolver); public static Set<Class<?>> scan() { String scanPath = ApplicationUtil.getApplicationContext().getEnvironment().getProperty(FULLTEXT_SACN_PACKAGE_PATH); if (!StringUtils.isEmpty(scanPath)) { return ClassScaner.scan(StringUtils.tokenizeToStringArray(scanPath, ",; \t\n")); } return null; } public static Set<Class<?>> scan(String[] basePackages) { ClassScaner cs = new ClassScaner(); Set<Class<?>> classes = new HashSet<Class<?>>(); for (String s : basePackages) { classes.addAll(cs.doScan(s)); } return classes; } @Override public void setResourceLoader(ResourceLoader resourceLoader) { this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader); this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader); } public Set<Class<?>> doScan(String basePackage) { Set<Class<?>> classes = new HashSet<Class<?>>(); try { String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX .concat(org.springframework.util.ClassUtils .convertClassNameToResourcePath(SystemPropertyUtils.resolvePlaceholders(basePackage)) .concat("/**/*.class")); Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath); MetadataReader metadataReader = null; for (Resource resource : resources) { if (resource.isReadable()) { metadataReader = this.metadataReaderFactory.getMetadataReader(resource); if ((includeFilters.size() == 0 && excludeFilters.size() == 0) || matches(metadataReader)) { try { classes.add(Class.forName(metadataReader.getClassMetadata().getClassName())); } catch (ClassNotFoundException e) { e.printStackTrace(); } } } } } catch (IOException ex) { throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex); } return classes; } protected boolean matches(MetadataReader metadataReader) throws IOException { for (TypeFilter tf : this.excludeFilters) { if (tf.match(metadataReader, this.metadataReaderFactory)) { return false; } } for (TypeFilter tf : this.includeFilters) { if (tf.match(metadataReader, this.metadataReaderFactory)) { return true; } } return false; } }
3.创建全文索引注解
import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.RetentionPolicy.RUNTIME; /** * 全文索引注解 * * @作者 light-zhang * @时间 2019年3月13日 * @product order * @package cc.zeelan.mall.order.common * @file FruitProvider.java * */ @Target(FIELD) @Retention(RUNTIME) @Documented public @interface Fulltext { /** * 索引名称 * * @return */ String IndexesName() default ""; /** * 对应的列 */ String columnName(); }
4.注解委托实现
import java.lang.reflect.Field; import java.util.List; import java.util.Objects; import java.util.Set; import javax.persistence.EntityManager; import javax.persistence.Query; import javax.persistence.Table; import org.hibernate.AnnotationException; import org.hibernate.Session; import org.hibernate.query.NativeQuery; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.context.annotation.Configuration; import org.springframework.data.jpa.repository.Modifying; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; /** * 全文索引注解实现 * * @作者 light-zhang * @时间 2019年3月13日 * @product order * @package cc.zeelan.mall.order.common.util * @file FulltextKeyImpl.java * @DLL */ @Configuration @Transactional public class FulltextDelegator implements CommandLineRunner { @Autowired private EntityManager entityManager; private Session session; @Override public void run(String... args) throws Exception { Set<Class<?>> clazzs = ClassScaner.scan(); if (!Objects.isNull(clazzs)) { for (Class<?> clazz : clazzs) { getAnnotation(clazz); } } } /** * 处理全文注解相关 * * @param clazz */ public void getAnnotation(Class<?> clazz) { Field[] fields = clazz.getDeclaredFields(); String indexName = null; for (Field field : fields) { if (field.isAnnotationPresent(Fulltext.class)) { Table table = clazz.getAnnotation(Table.class); if (StringUtils.isEmpty(table.name())) { throw new AnnotationException("@table(name=‘‘) specified for entity: ".concat(clazz.getName())); } Fulltext fulltextKey = field.getAnnotation(Fulltext.class); if (!StringUtils.isEmpty(fulltextKey.IndexesName())) { indexName = fulltextKey.IndexesName(); } else { indexName = table.name().concat("_").concat(fulltextKey.columnName()).concat("_idx"); } if (isExist(table.name(), indexName) > 0) {// 当存在索引就删除当前的旧索引 deleteIndex(table.name(), indexName); } createIndex(table.name(), indexName, fulltextKey.columnName()); } } entityManager.flush(); entityManager.close(); } /** * 创建全文索引 */ private void createIndex(String tableName, String indexName, String columnName) { final StringBuffer createIndex = new StringBuffer("CREATE FULLTEXT INDEX ");// 執行創建索引 createIndex.append(indexName); createIndex.append(" ON "); createIndex.append(tableName); createIndex.append("("); createIndex.append(columnName); createIndex.append(")"); excute(createIndex.toString());// 在执行创建全文索引操作 createIndex.setLength(0);// 清空 } /** * 删除索引 */ private void deleteIndex(String tableName, String indexName) { final StringBuffer deleteIndex = new StringBuffer("ALTER TABLE ");// 執行刪除索引 deleteIndex.append(tableName); deleteIndex.append(" DROP INDEX "); deleteIndex.append(indexName); excute(deleteIndex.toString());// 先执行删除索引操作 deleteIndex.setLength(0);// 清空 } /** * 索引是否存在 * * @return */ private int isExist(String tableName, String indexName) { final StringBuffer existIndex = new StringBuffer("SHOW INDEX FROM ");// 執行刪除索引 existIndex.append(tableName); existIndex.append(" WHERE key_name LIKE ‘"); existIndex.append(indexName.concat("%‘")); int result = excuteQuery(existIndex.toString()); existIndex.setLength(0); return result; } /** * 执行创建全文索引SQL * * @param sql * @return */ @Modifying(clearAutomatically = true) public int excute(String sql) { Query query = entityManager.createNativeQuery(sql); return query.executeUpdate(); } /** * 查询全文索引工具 * * @param sql * @return */ public int excuteQuery(String sql) { session = entityManager.unwrap(org.hibernate.Session.class); NativeQuery<?> query = session.createSQLQuery(sql); List<?> arrays = query.getResultList(); if (!CollectionUtils.isEmpty(arrays)) { return arrays.size(); } return 0; } }
5.使用方法
1.先在application.properties下面配置:fulltext.scan.package=xxx.xxx.entity 要扫描类的包路径
IndexesName:表示要生成的全文索引名称,如果不赋值的情况下默认的生成策略为:表名_列名_idx || columnName:对应的列名
@Column(name = "order_ids", columnDefinition = "text COLLATE utf8_unicode_ci COMMENT ‘订单ids‘ ") @Fulltext(columnName = "order_ids") private String orderIds;
原文:https://www.cnblogs.com/light-zhang/p/10653991.html
评论(0)