SpringBoot集成与应用Neo4j

文章目录

  • 前言
  • 集成
  • 使用
    • 定义实体
    • 配置
    • 定义Repository
    • 查询方法
      • 方式一:@Query
      • 方式二:Cypher语法构建器
      • 方式三:Example条件构建器
      • 方式四:DSL语法
    • 自定义方法
      • 自定义接口
      • 继承自定义接口
      • 实现自定义接口
        • neo4jTemplate
        • Neo4jClient
      • 自定义抽象类(执行与结果转换)

前言

本篇主要是对neo4j的集成应用,会给出普遍的用法,但不是很详细,如果需要详细的话,每种方式都可以单独一篇说明,但应用都是举一反三,并没有必要都进行详解,而且,一些特殊的用法也举例了,也给出了一个自定义方式的查询和结果转换,虽然算不上完美,但也是很简单的,也希望大家有所收获。

集成

使用高版本的Spring data,我boot版本2.7,下面两个依赖,随便引入一个就行,我试过都是可以地

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-neo4j</artifactId></dependency>
<!--两者任选其一,--><dependency><groupId>org.springframework.data</groupId><artifactId>spring-data-neo4j</artifactId><version>6.3.11</version></dependency>

使用

定义实体

我们先定义三个实体

  • job:作业实体
  • table:表实体
  • JobRelationship:关系实体
@Data
@Node("Job")
public class Job {@Id@GeneratedValueprivate Long id;private String name;@Propertyprivate String type;@Relationship("dep")private List<TableRelationship> tables;@Relationship("dep")private List<JobRelationship> jobs;
}
@Data
@Node
public class Table {@Id@GeneratedValueprivate Long id;private String name;private String type;@Relationship("dep")private List<Job> jobs;
}
@Data
@RelationshipProperties
public class JobRelationship {@Id@GeneratedValueprivate Long id;@TargetNodeprivate Job job;
}
@Data
@RelationshipProperties
public class TableRelationship {@Id@GeneratedValueprivate Long id;@TargetNodeprivate Table table;
}

上面三个实体的写法都一些不同,这里需要注意下:

  1. @Node:标注的实体为数据库对象实体,表示一个节点,其value值就是标签,如果不设置就是类名;
  2. @Id:标注的属性是主键字段;
  3. @GeneratedValue:主键字段,必须设置它的一个生成方式,如果是自己设置可以忽略;
  4. @Property标注的属性为数据库属性字段,可以不写这个注解,@Node标注的实体中的属性默认为数据库属性字段,同样,其value值也是数据库属性字段,也可以不写,类似做了映射;
  5. @Relationship:标注的属性为关系属性,值为关系的标签值,另一个值为关系的指向,默认从当前节点向外指向,类似关系型数据库的关系;
  6. @RelationshipProperties:标注的类为关系实体,是对@Relationship类型的描述;
  7. @TargetNode:标注的属性是关系中的目标节点;

更加详细说明在:spring Data Neo4j

配置

application.yml

spring:neo4j:uri: bolt://192.168.0.103:7687authentication:username: neo4jpassword: password

定义Repository

这里使用的是spring jpa的开发方式,它提供了增删改查的基础功能,定义如下:

@Repository
public interface TableRepository extends Neo4jRepository<Table, Long> {
}
@Repository
public interface JobRepository extends Neo4jRepository<Job, Long> {/*** 根据名称查找*/Job findByName(String name);/*** 节点name是否包含指定的值*/boolean existsByNameContaining(String name);/*** 强制删除节点*/Long deleteByName(String name);
}

那这个JPA的方式的话可以通过关键字和属性名定义查询方法,如上面的的findByName就可以实现通过名称查询,不需要写实现,这里只说这么多,详细的可以看:Spring Data JPA - Reference Documentation

查询方法

spring data提供的基础增删改查其实在在业务中是不够用的,但是,它额外的提供了一些条件构建器,使得我们可以借助一些快捷的API进行查询条件构造,以适应这些复杂查询,也就是动态语法。

方式一:@Query

说起JPA,自定义查询好像大多是用@Query注解进行标注的,比如:

    @Query("match(a:Job{name:$name}) return a")Job findByName2(@Param("name") String name);@Query("match(a:Job{name: $0) return a")List<Job> findByName3(@Param("name") String name);

这样的方式很简单是不是,但是存在的问题是,语句中的Job,name都是对应数据库里的标签和字段,所以这就和mybatis xml里的方式一样,如果数据库字段变更或标签变更需要全局替换。

方式二:Cypher语法构建器

Spring data提供了针对Cypher语法的构建器,可以让我们对复杂cypher的语法构建;

示例一:

match(a:Job) where a.name=‘liry’ return a order by a.id limit 1

// match(a:Job) where a.name='liry' return a order by a.id  limit 1// 创建节点对象:标签为 Job,别名 a  -> (a:Job)
Node temp = Cypher.node("Job").named("a");
// 构建查询声明对象
// 创建match查询:-> match(a:Job)
ResultStatement statement = Cypher.match(temp)// 添加条件:-> a.name=$name.where(temp.property("name").isEqualTo(Cypher.anonParameter(job.getName())))// 返回对象:return 别名 -> return a.returning(temp.getRequiredSymbolicName())// 排序:以属性id正序.orderBy(temp.property("id"))// 限制数量:1.limit(1)// 构建为语法对象.build();

示例二:

//  merge(a:Job{name:$name}) set a.type=$type return a// 构建参数
Map<String, Object> pro = new HashMap<>();
pro.put("name", job.getName());
// 创建节点对象:标签Job,别名a,并且设置参数  -> (a:Job{name:$name})
Node temp = Cypher.node("Job").named("a").withProperties(pro);
// 创建merge查询: -> merge(a:Job{name:$name})
ResultStatement statement = Cypher.merge(temp)// 设置值:-> a.type=$type.set(temp.property("type"),Cypher.anonParameter(job.getType()))// 返回对象:return别名 -> return a.returning(temp.getRequiredSymbolicName())// 构建声明对象.build();

示例三:

// MATCH (a:`Job` {name: $pcdsl01})-[r*..2]-(b:`Job`) RETURN a,b,r// 创建两个节点给,都死标签Job,别名分别是a,b,a节点关联属性name
Node node = Cypher.node("Job").named("a").withProperties("name", Cypher.anonParameter(name));
Node node2 = Cypher.node("Job").named("b");// 创建a-r-b的关系
Relationship r = node.relationshipBetween(node2).named("r").max(length);
// a-r->b
//        Relationship r = node.relationshipTo(node2).named("r").max(length);
// a<-r-b
//        Relationship r = node.relationshipFrom(node2).named("r").max(length);
// 创建match查询
ResultStatement statement = Cypher.match(r)// 返回对象.returning("a","b","r")// 构建声明对象.build();

这里的withProperties,我又用了另一种方式.withProperties("name", Cypher.anonParameter(name));,上面我传的是一个map,它这里其实很巧妙的做了一个适配,只要你以key value,那么便是偶数个参数,他会自动帮你绑定,或者传map也行。

方式三:Example条件构建器

Spring Data默认的Neo4jRepository是继承 了QueryByExampleExecutor,如下:

image-20231028185641361

那么它所能使用的方法是这些:

image-20231028222339087

其应用示例一:

// Neo4jRepository默认继承了example功能Job job = new Job();job.setName("liry");ExampleMatcher exampleMatcher = ExampleMatcher.matching().withMatcher("na", ExampleMatcher.GenericPropertyMatchers.endsWith());// 根据示例匹配器规则进行条件重组 查询List<Job> all1 = jobRepository.findAll(Example.of(job, exampleMatcher));// 精确查询List<Job> all2 = jobRepository.findAll(Example.of(job));List<Job> all3 = jobRepository.findAll(Example.of(job), Sort.by(Sort.Order.desc("id")));Page<Job> all4 = jobRepository.findAll(Example.of(job), PageRequest.of(1, 10));

示例二:

流处理查询

  Job job = new Job();job.setJobName(name);// 查询一个一个值Job one = jobRepository.findBy(Example.of(job), query -> query.oneValue());// lambda简化
//        Job one = jobRepository.findBy(Example.of(job), FluentQuery.FetchableFluentQuery::oneValue);// 查询countLong count = jobRepository.findBy(Example.of(job), query -> query.count());// lambda简化
//        Long count = jobRepository.findBy(Example.of(job), FluentQuery.FetchableFluentQuery::count);// 是否存在Boolean exist = jobRepository.findBy(Example.of(job), query -> query.exists());// lambda简化
//        Boolean exist = jobRepository.findBy(Example.of(job), FluentQuery.FetchableFluentQuery::exists);// 查询全部List<Job> list = jobRepository.findBy(Example.of(job), query -> query.all());// lambda简化
//                List<Job> list = jobRepository.findBy(Example.of(job), FluentQuery.FetchableFluentQuery::all);// 查询2个List<Job> list2 = jobRepository.findBy(Example.of(job),query -> query.stream().limit(2).collect(Collectors.toList()));// 查询并进行处理List<Object> list3 = jobRepository.findBy(Example.of(job),query -> query.stream().peek(d -> d.setName(d.getName() + "1")).collect(Collectors.toList()));// 查询并排序List<Job> list4 = jobRepository.findBy(Example.of(job),query -> query.sortBy(Sort.by(Sort.Order.asc("id")))).all();

上面这个流处理查询都可以用lambda表达式来处理。

注意:使用example查询时,不要有关联关系,不然他会报错,即不要有@Relationship这个注解

方式四:DSL语法

这个是借助DSL框架实现的语法构建,添加DSL依赖

        <dependency><groupId>com.querydsl</groupId><artifactId>querydsl-jpa</artifactId></dependency><dependency><groupId>com.querydsl</groupId><artifactId>querydsl-apt</artifactId></dependency>

添加插件

 <plugin><groupId>com.mysema.maven</groupId><artifactId>apt-maven-plugin</artifactId><version>1.1.3</version><executions><execution><goals><goal>process</goal></goals><configuration><outputDirectory>target/generated-sources/java</outputDirectory><processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor></configuration></execution></executions>
</plugin>
  1. 实体类上需要加上@Entity

但是只引入neo4j的依赖,是不行的,还需要jpa的依赖,因为JPA依赖数据库,所以可以先引入,生成之后,再删除掉。

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.28</version>
</dependency>

然后maven compile编译,一下,会在target/generated-sources/java目录下找到生成的Q类,把它复制到我们实体目录下

image-20231028192712827

  1. 继承接口QuerydslPredicateExecutor

    它的使用方式和Example一样。

    @Repository
    public interface JobRepository extends Neo4jRepository<Job, Long> ,  QuerydslPredicateExecutor<Job>{
    }
    

    这个接口下的功能都可以使用

    image-20231028222117957

示例一:

 QJob job = QJob.job;
// name=$nameIterable<Job> all = jobRepository.findAll(job.name.eq(name));// name like $name and type = $typeBooleanExpression exp = job.name.like(name).and(job.type.eq("test"));boolean exists = jobRepository.exists(exp);Iterable<Job> all1 = jobRepository.findAll(exp);
// 排序Iterable<Job> id = jobRepository.findAll(exp, Sort.by(Sort.Order.desc("id")));
// 分月Page<Job> all2 = jobRepository.findAll(exp, PageRequest.of(1, 10));// in查询  exp = job.name.in("liryc", "xx");jobRepository.findAll(exp);

示例二:

     // 查询一个一个值Job one = jobRepository.findBy(exp, query -> query.oneValue());// lambda简化//        Job one = jobRepository.findBy(exp, FluentQuery.FetchableFluentQuery::oneValue);// 查询countLong count = jobRepository.findBy(exp, query -> query.count());// lambda简化//        Long count = jobRepository.findBy(exp, FluentQuery.FetchableFluentQuery::count);// 是否存在Boolean exist = jobRepository.findBy(exp, query -> query.exists());// lambda简化//        Boolean exist = jobRepository.findBy(exp, FluentQuery.FetchableFluentQuery::exists);// 查询全部List<Job> list = jobRepository.findBy(exp, query -> query.all());// lambda简化//                List<Job> list = jobRepository.findBy(exp, FluentQuery.FetchableFluentQuery::all);// 查询2个List<Job> list2 = jobRepository.findBy(exp,query -> query.stream().limit(2).collect(Collectors.toList()));// 查询并进行处理List<Object> list3 = jobRepository.findBy(exp,query -> query.stream().peek(d -> d.setName(d.getName() + "1")).collect(Collectors.toList()));// 查询并排序List<Job> list4 = jobRepository.findBy(exp,query -> query.sortBy(Sort.by(Sort.Order.asc("id")))).all();

自定义方法

上面都是spring data自带的方法,已经可以实现大部分的复杂查询了,当时在业务层的时候我们一般不会把这些数据访问放在业务层中,这些都应该是置于底层作为最基本的数据能力,不该带入业务,并且也不该把数据访问的逻辑赤裸的放到业务层中,那么我们就会需要子党员方法。

自定义接口

public interface JobCustomRepository {/*** 查询所有*/Object selectAll();/*** 保持节点信息,会先判断是否存在*/Job saveCondition(Job job);/*** 创建或合并节点*/Job saveMerge(Job job);
}

继承自定义接口

@Repository
public interface JobRepository extends Neo4jRepository<Job, Long> , JobCustomRepository {}

实现自定义接口

@Component("jobCustomRepository")
public class JobCustomRepositoryImpl implements JobCustomRepository {
}

如此我们就可以在业务层中这样:

// 这里引入的接口,就具备了原本spring的能力,和你自定义的能力
@Autowiredprivate JobRepository jobRepository;
neo4jTemplate

在自定义中可以引入这个作为执行类,这个类实现Neo4jOperations,template它是支持直接写cypher语句的,比如下面这个

image-20231029002709607

image-20231029003215340

如果需要参数分离的话,参数占位用$,那么cypher语句应该是这样:

match(a) where a.name=$name return a

示例:

        // 方式一:template执行cql字符串String cql = String.format("merge(a:Job{name:'%s'}) set a.time=2 return a", job.getName());List<Job> all = neo4jTemplate.findAll(cql, Job.class);// 方式二:cypher语句cql = String.format("merge(a:Job{name:'%s'}) set a.time=$time return a", job.getName());Map<String, Object> param = new HashMap<>();param.put("time", 1);all = neo4jTemplate.findAll(cql, param, Job.class);// 方式三:Cypher构建声明对象Map<String, Object> pro = new HashMap<>();pro.put("name", job.getName());Node temp = Cypher.node("Job").named("a").withProperties(pro);ResultStatement statement = Cypher.merge(temp).set(temp.property("type"), Cypher.anonParameter(job.getType())).returning(temp.getRequiredSymbolicName()).build();List<Job> all1 = neo4jTemplate.findAll(statement, statement.getParameters(), Job.class);
Neo4jClient

除了neo4jTemplate还可以用neo4jClient

示例

        String cpl = "match(a) where a.name contains 'liry' return a limit 1";// 执行cypherResult run = client.getQueryRunner().run(cpl);// 结果获取的方式// **** 注意,下面的几种方式中,只能选用一种,在结果读取后,就不能在读取了 ****// 方式一:迭代器while (run.hasNext()) {Record d = run.next();// 这几个的结构差不多List<Pair<String, Value>> fields = d.fields();List<Value> values = d.values();Map<String, Object> stringObjectMap = d.asMap();System.out.println(d);}// 方式二:lambda// 或者直接获取列表List<Record> list = run.list();List<Record> dd = list.stream().map(d -> {List<Pair<String, Value>> fields = d.fields();List<Value> values = d.values();Map<String, Object> stringObjectMap = d.asMap();return d;}).collect(Collectors.toList());// 方式三:函数式接口List<Object> result = run.list(map -> {return map;});

这里有需要注意的地方,就是在run执行后,只能获取一次结果,如上代码所示,不论用那种方式进行结果的获取,都只能获取一次;

自定义抽象类(执行与结果转换)

但是很多人就会觉得这个方式需要自己处理结果集,确实,它的这个结果集不是很友好,所以我这里也提供一个结果处理案例;

我这里就直接贴已经完成的代码了,可以直接复制使用,同时这个类也提供了执行cypher语句的方法,和JPA一样。

package com.liry.neo.repository;import com.liry.neo.entity.RelationshipInfo;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.Supplier;
import org.neo4j.driver.internal.types.InternalTypeSystem;
import org.neo4j.driver.internal.value.NodeValue;
import org.neo4j.driver.types.MapAccessor;
import org.neo4j.driver.types.Relationship;
import org.neo4j.driver.types.TypeSystem;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.data.neo4j.core.Neo4jOperations;
import org.springframework.data.neo4j.core.Neo4jTemplate;
import org.springframework.data.neo4j.core.PreparedQuery;
import org.springframework.data.neo4j.core.mapping.EntityInstanceWithSource;
import org.springframework.data.neo4j.core.mapping.Neo4jMappingContext;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;/*** @author ALI* @since 2023/10/25*/
public abstract class AbstractCustomRepository implements ApplicationContextAware {protected ApplicationContext applicationContext;private Neo4jMappingContext neo4jMappingContext;private Neo4jTemplate neo4jTemplate;private static <T> Supplier<BiFunction<TypeSystem, MapAccessor, ?>> getAndDecorateMappingFunction(Neo4jMappingContext mappingContext, Class<T> domainType, @Nullable Class<?> resultType) {Assert.notNull(mappingContext.getPersistentEntity(domainType), "Cannot get or create persistent entity.");return () -> {BiFunction<TypeSystem, MapAccessor, ?> mappingFunction = mappingContext.getRequiredMappingFunctionFor(domainType);if (resultType != null && domainType != resultType && !resultType.isInterface()) {mappingFunction = EntityInstanceWithSource.decorateMappingFunction(mappingFunction);}return mappingFunction;};}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}private Neo4jMappingContext getNeo4jMappingContext() {if (neo4jMappingContext == null) {neo4jMappingContext = applicationContext.getBean(Neo4jMappingContext.class);}return neo4jMappingContext;}private Neo4jTemplate getNeo4jTemplate() {if (neo4jTemplate == null) {neo4jTemplate = applicationContext.getBean(Neo4jTemplate.class);}return neo4jTemplate;}/*** 执行cypher查询** @param domainType      实体类型* @param cypherStatement cypher语句* @param parameters      参数*/protected <T> Neo4jOperations.ExecutableQuery<T> createExecutableQuery(Class<T> domainType, String cypherStatement,Map<String, Object> parameters) {return createExecutableQuery(domainType, domainType, cypherStatement, parameters);}/*** 执行cypher查询** @param domainType      实体类型* @param resultType      返回的结果类型* @param cypherStatement cypher语句* @param parameters      参数*/protected <T> Neo4jOperations.ExecutableQuery<T> createExecutableQuery(Class<?> domainType, Class<T> resultType, String cypherStatement,Map<String, Object> parameters) {PreparedQuery.OptionalBuildSteps<T> step = PreparedQuery.queryFor(resultType).withCypherQuery(cypherStatement).withParameters(parameters);// 基本类型转换if (!Number.class.isAssignableFrom(resultType) && !Boolean.class.isAssignableFrom(resultType) && !String.class.isAssignableFrom(resultType)) {Supplier<BiFunction<TypeSystem, MapAccessor, ?>> mappingFunction = getAndDecorateMappingFunction(getNeo4jMappingContext(),domainType,resultType);step.usingMappingFunction(mappingFunction);}return getNeo4jTemplate().toExecutableQuery(step.build());}protected <T> T mapping(Class<T> domainType, NodeValue node) {Object apply = getMappingFunction(domainType).get().apply(InternalTypeSystem.TYPE_SYSTEM, node);return (T) ((EntityInstanceWithSource) apply).getEntityInstance();}protected RelationshipInfo mapping(Relationship node) {RelationshipInfo result = new RelationshipInfo();result.setStart(node.startNodeId());result.setEnd(node.endNodeId());result.setType(node.type());result.setId(node.id());return result;}/*** 结果映射** @param domainType 实体类型,也是结果类型* @return 映射方法*/protected <T> Supplier<BiFunction<TypeSystem, MapAccessor, ?>> getMappingFunction(Class<T> domainType) {return () -> {BiFunction<TypeSystem, MapAccessor, T> mappingFunction = getNeo4jMappingContext().getRequiredMappingFunctionFor(domainType);return EntityInstanceWithSource.decorateMappingFunction(mappingFunction);};}
}

之后我们自定义的Repository就要继承这个抽象类,以达到可以直接使用的功能,如下:

@Component("jobCustomRepository")
public class JobCustomRepositoryImpl extends AbstractCustomRepository implements JobCustomRepository {@Autowiredprivate Neo4jTemplate neo4jTemplate;
}

再定义一个关系实体:

@Data
public class RelationshipDto {private Long id;private Long start;private Long end;private String type;
}

然后我们查询并转换如下:

        String cpl = "match(a:Job)-[r*]-(b:Job) return a,b,r";// 执行cypherResult run = client.getQueryRunner().run(cpl);// 结果接受容器Set<Object> nodes = new HashSet<>();Set<Object> relationships = new HashSet<>();// 结果转换List<Record> list = run.list();list.forEach(d -> {// cypher中,别名a,b是表示节点,那么这里就取 a,b的值转换为实体nodes.add(mappingNode(Job.class, d.get("a")));nodes.add(mappingNode(Job.class, d.get("b")));// 然后获取关系Value r = d.get("r");Value a = d.get("a");List<Object> reList = r.asList().stream().map(rd -> {System.out.println(rd);return mappingRelationship((org.neo4j.driver.types.Relationship) rd);}).collect(Collectors.toList());relationships.addAll(reList);});

image-20231030210428356

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/124884.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Visual Studio(VS)C++项目 管理第三方依赖库和目录设置

发现很多程序员存在这种做法&#xff1a;把项目依赖的第三方库的lib和dll放在项目目录下&#xff0c;或者复制到输出目录&#xff0c;因为每种配置都有不同的输出目录&#xff0c;所以要复制多份&#xff08;至少包括Debug和Release两个输出目录&#xff09;&#xff0c;这些做…

MySQL -- 表的增删查改

MySQL – 表的增删查改 文章目录 MySQL -- 表的增删查改一、Create创建1.插入数据2.插入否则更新3.替换 二、Retrieve查找1.select列1.1.全列查询1.2.指定列查询1.3.查询字段为表达式1.4.为查询结果指定别名1.5.结果去重 2.where条件2.1.英语不及格的同学&#xff08;英语<6…

MA网络下,静态路由仅配出接口,不配下一跳是否可行

在MA网络模式下&#xff0c;静态路由只配置出接口&#xff0c;不配置下一跳地址是否可行 如下拓扑图&#xff1a; 如图所示&#xff0c;在R1上配置一条去往4.4.4.4的静态路由&#xff0c;此时如果静态路由只配置出接口&#xff0c;不配置下一跳地址&#xff1a; ip route-stat…

山河CTF(部分write up)

MISC [WEEK1]签到题 下载题目并打开&#xff1a; base128编码&#xff1a; Wm14aFozdDBhR2x6WDJselgyWnNZV2Q5 因为是base128编码&#xff0c;所以通过两次base64解码&#xff0c;即可得出flag 爆出flag&#xff1a; flag{this_is_flag} 总结&#xff1a; 这道签到题主要考察了…

Linux MeterSphere测试平台远程访问你不会?来试试这篇文章

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏:《粉丝福利》 《C语言进阶篇》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 前言1. 安装MeterSphere2. 本地访问MeterSphere3. 安装 cpolar内网穿透软件4. 配置MeterSphere公网访问地址5. 公网…

[C++]命名空间等——喵喵要吃C嘎嘎

希望你开心&#xff0c;希望你健康&#xff0c;希望你幸福&#xff0c;希望你点赞&#xff01; 最后的最后&#xff0c;关注喵&#xff0c;关注喵&#xff0c;关注喵&#xff0c;大大会看到更多有趣的博客哦&#xff01;&#xff01;&#xff01; 喵喵喵&#xff0c;你对我真的…

目标检测 YOLOv5 预训练模型下载方法

目标检测 YOLOv5 预训练模型下载方法 flyfish https://github.com/ultralytics/yolov5 https://github.com/ultralytics/yolov5/releases 可以选择自己需要的版本和不同任务类型的模型 后缀名是pt

MongoDB的安装

MongoDB的安装 1、Windows下MongoDB的安装及配置 1.1 下载Mongodb安装包 下载地址&#xff1a; https://www.mongodb.com/try/download http://www.mongodb.org/dl/win32 MongoDB Windows系统64位下载地址&#xff1a;http://www.mongodb.org/dl/win32/x86_64 MongoDB W…

python采集电商jd app商品详情数据(2023-10-30)

一、技术要点&#xff1a; 1、cookie可以从手机app端用charles抓包获取&#xff1b; 2、无需安装nodejs&#xff0c;纯python源码&#xff1b; 3、商品详情接口为&#xff1a;functionId "wareBusiness"&#xff1b; 4、clientVersion "10.1.4"同…

java阵道之适配器大阵

开个玩笑&#xff0c;这里是一篇适配器模式讲解 定义&#xff1a; 适配器模式将某个类的接口转换成客户端期望的另一个接口表示&#xff0c;目的是消除由于接口不匹配所造成的类的兼容性问题。 主要分为三类&#xff1a;类的适配器模式、对象的适配器模式、接口的适配器模式。…

【原创】java+swing+mysql志愿者管理系统设计与实现

摘要&#xff1a; 志愿者管理系统是一个用于管理志愿者以及活动报名的系统&#xff0c;提高志愿者管理的效率&#xff0c;同时为志愿者提供更好的服务和体验。本文主要介绍如何使用javaswingmysql去实现一个志愿者管理系统。 功能分析&#xff1a; 系统主要提供给管理员和志…

洞察运营机会的数据分析利器

这套分析方法包括5个分析工具&#xff1a; 用“描述性统计”来快速了解数据的整体特点。用“变化分析”来寻找数据的问题和突破口。用“指标体系”来深度洞察变化背后的原因。用“相关性分析”来精确判断原因的影响程度。用“趋势预测”来科学预测未来数据的走势&#xff0c;

少儿编程 2023年9月中国电子学会图形化编程等级考试Scratch编程四级真题解析(选择题)

2023年9月scratch编程等级考试四级真题 选择题(共25题,每题2分,共50分) 1、角色为一个紫色圆圈,运行程序后,舞台上的图案是 A、 B、 C、 D、 答案:A

阿里云推出通义千问App,提供全方位的协助

&#x1f989; AI新闻 &#x1f680; 阿里云推出通义千问App&#xff0c;提供全方位的协助 摘要&#xff1a;阿里云旗下大模型通义千问App登陆各大安卓应用市场&#xff0c;具有超大规模预训练模型&#xff0c;可在创意文案、办公助理、学习助手、趣味生活等方面协助用户。功…

Redis测试新手入门教程

在测试过程中&#xff0c;我们或多或少会接触到Redis&#xff0c;今天就把在小破站看到的三丰老师课程&#xff0c;把笔记整理了下&#xff0c;用来备忘&#xff0c;也希望能给大家带来亿点点收获。 主要分为两个部分&#xff1a; 一、缓存技术在后端架构中是如何应用的&#…

10.31一些代码分析,香浓展开,移位器(桶形多位),二进制转格雷码

always的block之间&#xff0c;采用并行执行 always之内&#xff0c;采用非阻塞赋值&#xff0c;为顺序执行 一些代码分析 这个把使能信号和W信号组合在一起&#xff0c;进行case语句&#xff0c;即只有合并信号最高位为1时&#xff0c;才进行操作 always后面要写&#xff0…

非科班出身的野生Android也可以跳到大厂

野生Android从业者&#xff0c;非科班出身&#xff0c;在小公司打杂2年后&#xff0c;"意外"地拿到了大厂的offer。 高中毕业后&#xff0c;我选择了一条不太寻常的路&#xff0c;&#xff08;花大几万&#xff09;进入编程培训班&#xff0c;后来又自修课程&#xf…

信创强国 | 安全狗荣获信创工委会技术活动单位证书

近日&#xff0c;安全狗荣获中国电子工业标准化技术协会信息技术应用创新工作委员会&#xff08;以下简称“信创工委会”&#xff09;颁发的信息技术应用创新工作委员会技术活动单位证书。 作为国内云原生安全领导厂商&#xff0c;安全狗在信息技术应用创新方面有多年的技术积累…

超全整理,Jmeter性能测试-脚本error报错排查/分布式压测(详全)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 性能脚本error报错…

OPENCV 闭运算实验示例代码morphologyEx()函数

void CrelaxMyFriendDlg::OnBnClickedOk() {hdc this->GetDC()->GetSafeHdc();// TODO: 在此添加控件通知处理程序代码string imAddr "c:/Users/actorsun/Pictures/";string imAddr1 imAddr"rice.png";Mat relax, positive;relax imread(imAddr1…