SpringBoot该怎么使用Neo4j - 优化篇
前言
上一篇中,我们的Cypher
都用的是字符串,字符串拼接简单,但存在写错的风险,对于一些比较懒的开发者,甚至觉得之间写字符串还更自在快速,也确实,但如果在后期需要修改,如更高字段名或者一些级联的变动,会导致维护难,所以,这里这里我们模仿Mybatis-Plus
写一个实体字段工具之间替换哪些字符串,以提高项目可维护性。
如需要了解上篇,位置:SpringBoot该怎么使用Neo4j
实体工具
我们以这篇的工具为基础进行下面的开发:Lambda表达式提取字段名-CSDN博客
然后我们再增加对于与Neo4j
的实体工具:
-
实体缓存对象信息,保存实体必要信息
public class EntityCache { private String className; private List<String> labels; private Map<String, String> fieldNameMap; public String getClassName() { return className; } public void setClassName(String className) { this.className = className; } public List<String> getLabels() { return labels; } public void setLabels(List<String> labels) { this.labels = labels; } public Map<String, String> getFieldNameMap() { return fieldNameMap; } public void setFieldNameMap(Map<String, String> fieldNameMap) { this.fieldNameMap = fieldNameMap; } }
-
解析工具,也就是反射解析
public class EntityUtil { /** * 实体缓存 */ private static final Map<String, EntityCache> ENTITY_MAP = new ConcurrentHashMap<>(); public static void main(String[] args) { Job job = new Job(); String column = column(Job::getName); System.out.println(column); System.out.println(label(Job.class)); } /** * 从lambda转换出字段名 */ public static <T, R> String column(CusFunction<T, R> column) { SerializedLambda resolve = LambdaUtils.resolve(column); return getColumn(LambdaUtils.getClass(resolve), LambdaUtils.getMethodName(resolve) , true); } /** * 从实体class解析出标签 */ public static <T> String label(Class<T> clazz) { EntityCache info = ENTITY_MAP.putIfAbsent(clazz.getTypeName(), resolve(clazz)); return info.getLabels().get(0); } /** * 根据类型和方法名解析字段名 * @param aClass 类型 * @param methodName 方法名 * @param dbField 是否数据库字段 * @return 字段名 */ private static String getColumn(Class<?> aClass, String methodName, boolean dbField) { String fieldName = PropertyNamer.methodToProperty(methodName); if (!dbField) { return fieldName; } EntityCache info = resolve(aClass); if (!StringUtils.hasLength(fieldName)) { throw new RuntimeException(String.format("找不到实体对应的字段-[%s.%s]", aClass.getTypeName(), methodName)); } Map<String, String> map = info.getFieldNameMap(); return map.get(fieldName); } /** * 解析实体 * @param clazz 类型 * @return 实体缓存对象 */ public static <T> EntityCache resolve(Class<T> clazz) { String typeName = clazz.getTypeName(); EntityCache info = ENTITY_MAP.get(typeName); if (info != null) { return info; } Field[] declaredFields = clazz.getDeclaredFields(); Map<String, String> fieldNameMap = new HashMap<>(); for (Field declaredField : declaredFields) { declaredField.setAccessible(true); String fieldName = declaredField.getName(); String dbFieldName = fieldName; Property property = declaredField.getAnnotation(Property.class); if (property != null) { if (StringUtils.hasLength(property.name())) { dbFieldName = property.name(); } if (StringUtils.hasLength(property.value())) { dbFieldName = property.value(); } } fieldNameMap.put(fieldName, dbFieldName); } List<String> labelList = resolveLabel(clazz); info = new EntityCache(); info.setLabels(labelList); info.setClassName(typeName); info.setFieldNameMap(fieldNameMap); ENTITY_MAP.put(typeName, info); return info; } /** * 解析标签 * @param clazz 类型 * @return 标签列表 */ private static <T> List<String> resolveLabel(Class<T> clazz) { Node node = clazz.getAnnotation(Node.class); if (node == null) { throw new RuntimeException("非数据库实体对象实体!"); } String[] value = node.value(); String[] labels = node.labels(); List<String> result = new ArrayList<>(); result.addAll(Arrays.asList(value)); result.addAll(Arrays.asList(labels)); if (result.isEmpty()) { result.add(clazz.getSimpleName()); } return result; } }
-
测试:
@Test public void testEntity() { String column = EntityUtil.column(Job::getName); EntityUtil.label(Job.class); String column1 = EntityUtil.column(Job::getJobName); System.out.println(column +" " + column1); }
使用
实际开发中,就可以将字符串进行替换,如下面:
查询标签Job
,name='liry'
,并通过id
顺序排序,取第一个的cypher
构建
// match(a:Job) where a.name='liry' return a order by a.id limit 1
Node temp = Cypher.node("Job").named("a");
ResultStatement statement = Cypher.match(temp)
.where(temp.property("name").isEqualTo(Cypher.anonParameter(job.getName())))
.returning(temp.getRequiredSymbolicName())
.orderBy(temp.property("id"))
.limit(1)
.build();
进行替换
// match(a:Job) where a.name='liry' return a order by a.id limit 1
// 字符串 Job -> EntityUtil.label(Job.class)
// 字符串 name -> EntityUtil.column(Job::getName)
// 字符串 id -> EntityUtil.column(Job::getId)
Node temp = Cypher.node(EntityUtil.label(Job.class)).named("a");
ResultStatement statement = Cypher.match(temp)
.where(temp.property(EntityUtil.column(Job::getName)).isEqualTo(Cypher.anonParameter(job.getName())))
.returning(temp.getRequiredSymbolicName())
.orderBy(temp.property(EntityUtil.column(Job::getId)))
.limit(1)
.build();
创建一个节点:
create (a:Job{name:'liry',jobName:'liry-job'}) return a;
可以看到调试中构建的Cypher
是正确的。
原文地址:https://blog.csdn.net/qq_28911061/article/details/144246948
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!