04-SpringBoot集成Nebula Graph

2023-11-17

SpringBoot集成Nebula

建议模块

在这里给大家推荐一种方式, 每引入一种新的技术,建议新建一个模块, 来适配这种技术,对外提供接口,在调用的地方应用就可以, 不用搞的到处都是, 防止如果后续替换这种技术, 还要到处修改, 这样的话, 只需要增加一个模块, 对外提供一样的接口, 并替换依赖就可以

添加Maven依赖

<dependency>
  <groupId>com.vesoft</groupId>
  <artifactId>client</artifactId>
  <version>3.0.0</version>
</dependency>
<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>fastjson</artifactId>
  <version>1.2.83</version>
</dependency>

配合FastJson一起用比较方便, 为了解决fastjson漏洞问题, 使用1.2.83及其以上版本

增加yml配置

nebula:
  address[0]:
    host: 192.168.247.130
    port: 9669
  username: root
  password: 123456
  reconnect: false
  space: knowledge_extraction_platform

address[0]: 因为是开发, 所以配置为单机的, 等部署生产的话, 可以增加address[1-..]来完成集群的配置

space: 图空间

新增配置类

主机和端口

package com.jd.knowledgeextractionplatform.nebulagraph.config;

import lombok.Data;

@Data
public class NebulaAddress {
    private String host;
    private Integer port;
}

解析配置文件的模型

package com.jd.knowledgeextractionplatform.nebulagraph.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import java.util.List;

@Data
@Configuration
@ConfigurationProperties(prefix = "nebula")
public class NebulaProperties {
    private List<NebulaAddress> address;
    private String username;
    private String password;
    private boolean reconnect;
    private String space;
}

基于配置初始化会话和连接池

package com.jd.knowledgeextractionplatform.nebulagraph.config;

import com.jd.knowledgeextractionplatform.nebulagraph.constant.NebulaConstant;
import com.sun.javafx.binding.StringFormatter;
import com.vesoft.nebula.client.graph.NebulaPoolConfig;
import com.vesoft.nebula.client.graph.data.HostAddress;
import com.vesoft.nebula.client.graph.net.NebulaPool;
import com.vesoft.nebula.client.graph.net.Session;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;

import java.util.stream.Collectors;

@Slf4j
@Configuration
public class NebulaConfig {
    
    @Bean
    public NebulaPool nebulaPool(NebulaProperties nebulaProperties) throws Exception {
        NebulaPool pool = new NebulaPool();
        NebulaPoolConfig nebulaPoolConfig = new NebulaPoolConfig();
        nebulaPoolConfig.setMaxConnSize(1000);
        boolean init = pool.init(nebulaProperties.getAddress().stream().map(d -> new HostAddress(d.getHost(), d.getPort())).collect(Collectors.toList()), nebulaPoolConfig);
        if (!init){
            throw new RuntimeException("NebulaGraph init err !");
        }else {
            log.info("NebulaGraph init Success !");
        }
        return pool;
    }
    
    @Bean
    @Scope(scopeName = "prototype",proxyMode = ScopedProxyMode.TARGET_CLASS)
    public Session session(NebulaPool nebulaPool, NebulaProperties nebulaProperties) {
        try {
            Session session = nebulaPool.getSession(nebulaProperties.getUsername(), nebulaProperties.getPassword(), nebulaProperties.isReconnect());
            session.execute(StringFormatter.concat(NebulaConstant.USE, nebulaProperties.getSpace(), NebulaConstant.SEMICOLON).getValue());
            return session;
        } catch (Exception e) {
            log.error("get nebula session err , {} ", e.toString());
        }
        return null;
    }
}

常用常量(用于返回结果)

package com.jd.knowledgeextractionplatform.nebulagraph.constant;

import lombok.AllArgsConstructor;
import lombok.Getter;

public class NebulaConstant {
    public static final String USE = "USE ";
    public static final String SEMICOLON = "; ";
    public static final String ERROR_CODE = "-1";

    @Getter
    @AllArgsConstructor
    public enum NebulaJson{
        ERRORS("errors"),
        CODE("code"),
        MESSAGE("message"),
        RESULTS("results"),
        COLUMNS("columns"),
        DATA("data"),
        ROW("row");
        private String key;
    }
}

图数据库通用返回结果

package com.jd.knowledgeextractionplatform.nebulagraph.result;

import lombok.Data;

import java.util.List;

@Data
public class NebulaResult<T> {
    private Integer code;
    private String message;
    private List<T> data;

    public boolean isSuccessed(){
        return code == 0;
    }
}

为了防止每次都解析图数据库返回的结果,增加Template

package com.jd.knowledgeextractionplatform.nebulagraph.template;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jd.knowledgeextractionplatform.nebulagraph.constant.NebulaConstant;
import com.jd.knowledgeextractionplatform.nebulagraph.result.NebulaResult;
import com.vesoft.nebula.client.graph.data.ResultSet;
import com.vesoft.nebula.client.graph.exception.IOErrorException;
import com.vesoft.nebula.client.graph.net.Session;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Component
public class NebulaTemplate {

    @Resource
    Session session;

    public <T> NebulaResult<T> queryObject(String stmt, Class<T> tClass) {
        NebulaResult<T> nebulaResult = executeObject(stmt);
        if (Objects.isNull(nebulaResult.getData())) {
            return nebulaResult;
        }
        Optional.ofNullable(nebulaResult.getData()).ifPresent(data -> nebulaResult.setData(data.stream().map(d -> JSONObject.toJavaObject(((JSONObject) d), tClass)).collect(Collectors.toList())));
        return nebulaResult;
    }

    public NebulaResult executeObject(String stmt) {
        JSONObject jsonObject = executeJson(stmt);
        return JSONObject.toJavaObject(jsonObject, NebulaResult.class);
    }

    public JSONObject executeJson(String stmt) {
        JSONObject restJson = new JSONObject();
        try {
            JSONObject jsonObject = JSON.parseObject(Objects.requireNonNull(session).executeJson(stmt));
            JSONObject errors = jsonObject.getJSONArray(NebulaConstant.NebulaJson.ERRORS.getKey()).getJSONObject(0);
            restJson.put(NebulaConstant.NebulaJson.CODE.getKey(), errors.getInteger(NebulaConstant.NebulaJson.CODE.getKey()));
            if (errors.getInteger(NebulaConstant.NebulaJson.CODE.getKey()) != 0) {
                restJson.put(NebulaConstant.NebulaJson.MESSAGE.getKey(), errors.getString(NebulaConstant.NebulaJson.MESSAGE.getKey()));
                return restJson;
            }
            JSONObject results = jsonObject.getJSONArray(NebulaConstant.NebulaJson.RESULTS.getKey()).getJSONObject(0);
            JSONArray columns = results.getJSONArray(NebulaConstant.NebulaJson.COLUMNS.getKey());
            if (Objects.isNull(columns)) {
                return restJson;
            }
            JSONArray data = results.getJSONArray(NebulaConstant.NebulaJson.DATA.getKey());
            if (Objects.isNull(data)) {
                return restJson;
            }
            List<JSONObject> resultList = new ArrayList<>();
            data.stream().map(d -> (JSONObject) d).forEach(d -> {
                JSONArray row = d.getJSONArray(NebulaConstant.NebulaJson.ROW.getKey());
                JSONObject map = new JSONObject();
                for (int i = 0; i < columns.size(); i++) {
                    map.put(columns.getString(i), row.get(i));
                }
                resultList.add(map);
            });
            restJson.put(NebulaConstant.NebulaJson.DATA.getKey(), resultList);
        } catch (Exception e) {
            restJson.put(NebulaConstant.NebulaJson.CODE.getKey(), NebulaConstant.ERROR_CODE);
            restJson.put(NebulaConstant.NebulaJson.MESSAGE.getKey(), e.toString());
            log.error("nebula execute err:", e);
        }
        return restJson;
    }
}

使用

在Service中引入依赖

为了放置每次都构建nGQL, 虽然灵活, 但是使用困难较大, 有学习成本, 我建立了一个SqlBuildUtils的工具类

扩展

引入SqlBuild

package com.jd.knowledgeextractionplatform.nebulagraph.utils;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.validation.constraints.NotNull;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class SqlBuild {

    private Long id;

    private String name;

    private String field;

    private String values;

}

引入SqlBuildUtils

package com.jd.knowledgeextractionplatform.nebulagraph.utils;

import com.jd.knowledgeextractionplatform.nebulagraph.annotation.ClassAutoMapping;
import com.jd.knowledgeextractionplatform.nebulagraph.annotation.FieldAutoMapping;
import com.jd.knowledgeextractionplatform.nebulagraph.model.Edge;
import com.jd.knowledgeextractionplatform.nebulagraph.model.ModelAndClass;
import com.jd.knowledgeextractionplatform.nebulagraph.model.ProjectModelAndClass;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Locale;

@Component
public class SqlBuildUtils {

    private static final String methodPre = "get";

    private static final String insertTagSqlTemplate = "insert vertex %s(%s) values \"%s\":(%s);";

    private static final String insertEdgeSqlTemplate = "insert edge %s(%s) values \"%s\" -> \"%s\":(%s);";

    private static final String deleteTagSqlTemplate = "delete tag %s from \"%s\";";

    private static final String deleteEdgeSqlTemplate = "delete edge %s \"%s\" -> \"%s\"@0;";

    private static final String deleteVertexSqlTemplate = "delete vertex \"%s\" with edge;";

    private static final String updateVertexSqlTemplate = "update vertex on %s \"%s\" set %s;";

    private static final String createTag = "create tag if not exists %s(id int64, name String,description String) comment = \"%s\";";

    private static final String insertDefaultVertex = "insert vertex if not exists %s(id,name,description) values \"%s\":(%s,\"%s\",\"%s\");";

    private static final String insertDefaultEdge = "insert edge %s(id,name) values \"%s\" -> \"%s\":(%s,\"%s\");";

    private static final String dropTagSqlTemplate = "drop tag if exists %s;";

    private static final String dropEdgeSqlTemplate = "drop edge if exists %s;";

    private static final String createEdgeSqlTemplate = "create edge if not exists %s(id int64,name String) comment = \"%s\"";

    public static <T> String buildInsert(T t) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        SqlBuild tag = parse(t);
        return String.format(insertTagSqlTemplate, tag.getName(), tag.getField(), tag.getId(), tag.getValues());
    }

    public static <T extends Edge> String buildEdge(T t) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        SqlBuild edge = parse(t);
        return String.format(insertEdgeSqlTemplate, edge.getName(), edge.getField(), t.getLeftVid(), t.getRightVid(), edge.getValues());
    }

    public static <T> String deleteTag(T t) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
        SqlBuild tag = parse(t);
        return String.format(deleteTagSqlTemplate,tag.getName(),tag.getId());
    }

    public static String deleteEdge(String edgeName, Long pid, Long subId){
        return String.format(deleteEdgeSqlTemplate,edgeName,pid,subId);
    }

    public static <T> String deleteVertex(Long id){
        return String.format(deleteVertexSqlTemplate,id);
    }

    public static <T> String updateVertex(T t) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
        Class<?> clazz = t.getClass();
        ClassAutoMapping annotation = clazz.getAnnotation(ClassAutoMapping.class);
        String tagName = annotation.value();
        Field[] declaredFields = clazz.getDeclaredFields();
        StringBuilder set = new StringBuilder();
        Long id = null;
        for (int i = 0; i < declaredFields.length; i++) {
            Field declaredField = declaredFields[i];
            // 获取属性名称
            String name = declaredField.getName();
            // 获取自定义注解 FieldAutoMapping
            FieldAutoMapping autoMapping = declaredField.getAnnotation(FieldAutoMapping.class);
            if(null == autoMapping){
                continue;
            }
            String methodName = autoMapping.method();
            String type = autoMapping.type();
            Method getMethod = clazz.getDeclaredMethod(methodName);
            Object value = getMethod.invoke(t);
            Object valueFormat = format(value, type);
            if ("id".equals(name)) {
                id = (Long) value;
                continue;
            }
            set.append(name).append("=").append(valueFormat);
            if (i != declaredFields.length - 1) {
                set.append(",");
            }
        }
        return String.format(updateVertexSqlTemplate,tagName,id,set.toString());
    }

    public static String updateDefault(String tagName,Long vid,String name, String description){
        String setCall = "name="+format(name,"String")+",description="+format(description,"String");
        return String.format(updateVertexSqlTemplate,tagName,vid,setCall);
    }

    private static <T> SqlBuild parse(T t) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Class<?> clazz = t.getClass();
        ClassAutoMapping annotation = clazz.getAnnotation(ClassAutoMapping.class);
        String tagName = annotation.value();
        Field[] declaredFields = clazz.getDeclaredFields();
        StringBuilder filedString = new StringBuilder();
        StringBuilder valueString = new StringBuilder();
        Long id = null;
        for (int i = 0; i < declaredFields.length; i++) {
            Field declaredField = declaredFields[i];
            // 获取属性名称
            String name = declaredField.getName();
            // 获取自定义注解 FieldAutoMapping
            FieldAutoMapping autoMapping = declaredField.getAnnotation(FieldAutoMapping.class);
            if(null == autoMapping){
                continue;
            }
            String methodName = autoMapping.method();
            String type = autoMapping.type();
            Method getMethod = clazz.getDeclaredMethod(methodName);
            Object value = getMethod.invoke(t);
            filedString.append(name);
            Object valueFormat = format(value, type);
            if ("id".equals(name)) {
                id = (Long) value;
            }
            valueString.append(valueFormat);
            if (i != declaredFields.length - 1) {
                filedString.append(",");
                valueString.append(",");
            }
        }
        return new SqlBuild(id,tagName,filedString.toString(),valueString.toString());
    }

    public static String createTag(String tagName,String comment){
        return String.format(createTag,tagName,comment);
    }

    public static String createEdge(String edgeName,String comment){
        return String.format(createEdgeSqlTemplate,edgeName,comment);
    }

    public static String insertDefaultVertex(String tagName,Long vid,String name,String description){
        return String.format(insertDefaultVertex,tagName,vid,vid,name,description);
    }

    public static String dropTag(String tagName){
        return String.format(dropTagSqlTemplate,tagName);
    }

    public static String dropEdge(String edgeName){
        return String.format(dropEdgeSqlTemplate,edgeName);
    }

    public static String insertDefaultEdge(String edgeCode,Long pid,Long id,Long preId,String edgeName){
        return String.format(insertDefaultEdge,edgeCode,pid,id,preId,edgeName);
    }

    /**
     * 首字母转大写
     *
     * @param name 字符串
     * @return 转大写
     */
    private static String firstCharacterToUppercase(String name) {
        String startName = name.substring(0, 1);
        String endName = name.substring(1);
        return startName.toUpperCase(Locale.ROOT) + endName;
    }

    private static Object format(Object value, String type) {
        if ("String".equals(type)) {
            String s = value + "";
            return "\"" + s + "\"";
        }
        return value;
    }

    public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
        // 测试点生成
        ModelAndClass modelAndClass = new ModelAndClass();
        modelAndClass.setId(123123123123L);
        modelAndClass.setName("模式");
        modelAndClass.setPid(132313231313123L);
        modelAndClass.setDescription("描述");
        String s = buildInsert(modelAndClass);
        System.out.println(s);
        // 测试边生成
        ProjectModelAndClass projectModelAndClass = new ProjectModelAndClass();
        projectModelAndClass.setStartId(181314024706908160L);
        projectModelAndClass.setEndId(123123123123L);
        projectModelAndClass.setLeftVid("181314024706908160");
        projectModelAndClass.setRightVid("123123123123");
        String s1 = buildEdge(projectModelAndClass);
        System.out.println(s1);
    }

}

引入注解

类注解
package com.jd.knowledgeextractionplatform.nebulagraph.annotation;

import java.lang.annotation.*;

@Documented
@Target({ElementType.TYPE,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ClassAutoMapping {

    String value() default "";

}
字段注解
package com.jd.knowledgeextractionplatform.nebulagraph.annotation;

import java.lang.annotation.*;

@Documented
@Target({ElementType.TYPE,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface FieldAutoMapping {

    String method() default "";

    String type();

}

引入边的通用属性

package com.jd.knowledgeextractionplatform.nebulagraph.model;

import lombok.Data;

@Data
public class Edge {

    private String leftVid;

    private String rightVid;

}

使用方式

节点使用方式

在节点类上增加注解

package com.jd.knowledgeextractionplatform.nebulagraph.model;

import com.jd.knowledgeextractionplatform.nebulagraph.annotation.ClassAutoMapping;
import com.jd.knowledgeextractionplatform.nebulagraph.annotation.FieldAutoMapping;
import lombok.Data;

import java.io.Serializable;

@Data
@ClassAutoMapping("modelandclass")
public class ModelAndClass implements Serializable {

    /**
     * id vid
     */
    @FieldAutoMapping(method = "getId", type = "Long")
    private Long id;

    /**
     * 父级ID
     */
    @FieldAutoMapping(method = "getPid", type = "Long")
    private Long pid;/**
     * 名称
     */
    @FieldAutoMapping(method = "getName", type = "String")
    private String name;

    /**
     * 描述
     */
    @FieldAutoMapping(method = "getDescription", type = "String")
    private String description;

}
边使用方式

增加注解并继承边的通用属性

package com.jd.knowledgeextractionplatform.nebulagraph.model;

import com.jd.knowledgeextractionplatform.nebulagraph.annotation.ClassAutoMapping;
import com.jd.knowledgeextractionplatform.nebulagraph.annotation.FieldAutoMapping;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@AllArgsConstructor
@NoArgsConstructor
@ClassAutoMapping("project_attributeandrelationship")
public class ProjectAttributeAndRelationship extends Edge implements Serializable {

    @FieldAutoMapping(method = "getStartId",type = "Long")
    private Long startId;

    @FieldAutoMapping(method = "getEndId",type = "Long")
    private Long endId;

}

剩余的在Controller中传入模型的数据就可以了

其他Demo[直接写NGQL]

@RestController
public class TestController {

    @Resource
    NebulaTemplate nebulaTemplate;

    @GetMapping("/addVertex")
    public Object addJSON() throws IOErrorException {
        String sql = "insert vertex team(team_name, persion_num) values \"team_2\":(\"team_2\", 43);";
        NebulaResult nebulaResult = nebulaTemplate.executeObject(sql);
        return nebulaResult;
    }

    @GetMapping("/findVertex")
    public Object findJson2() throws IOErrorException {
        String sql = "lookup on team  yield id(vertex) AS id,properties(vertex).persion_num AS persion_num,properties(vertex).team_name AS team_name;";
        NebulaResult<Info> infoNebulaResult = nebulaTemplate.queryObject(sql, Info.class);
        return infoNebulaResult;
    }
}

查询的语句, 要自己写, 这个SqlBuildUtils只能统一解决节点tag和边edge的增删改问题

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

04-SpringBoot集成Nebula Graph 的相关文章

  • eclipse juno 打开时出错

    在安装 Eclipse 并正常工作一年多后 我今天打开 Eclipse Juno 并在打开工作区时收到一条错误消息 我使用的是 Windows 8 64 位 Java 64 位和 Eclipse 64 位 此后我尝试重新安装 Java 和
  • GSON:自定义对象反序列化

    好吧 我编辑了这个问题 因为它不够清楚 Edit 2 更新了 JSON 文件 我在 Android 应用程序中使用 GSON 我需要解析来自服务器的 JSON 文件 而且有点太复杂了 我不想让我的对象结构太重 所以我想简化内容 所以我的对象
  • Java 中的本机方法

    我花了一些时间学习什么是 Java Native 方法以及它们是在平台相关代码 主要是 C 中实现的 但是我在哪里可以找到这些 Java 的本机实现呢 例如 Thread 类的 sleep long millis 方法是本机的 但它的实现代
  • org.hibernate.MappingException:没有 JDBC 类型的方言映射:1111

    我使用的是 postgres v8 3 它的列类型为 XML DDL 看起来像这样 CREATE TABLE contact ID INTEGER NOT NULL NAME VARCHAR NOT NULL Details XML 在映射
  • Keycloak 社交登录 REST API

    我已经为我的 keycloak 实例启用了谷歌社交登录 但我需要将其用作休息服务 是否有可用于执行此操作的端点 Keycloak 中没有 Google 身份验证 API 但您可以使用以下方法解决它代币交换 https www keycloa
  • 在 javafx 中注册鼠标处理程序,但处理程序不是内联的

    我有一个 JavaFX 应用程序变得有点大 我想保持代码的可读性 我有一个折线图 我希望内置缩放功能 该功能在单击鼠标时发生 我知道我需要向图表注册鼠标侦听器 我无法从 Oracle 示例中弄清楚什么 即如下所示 http docs ora
  • 在 JSON 对象中强制执行非空字段

    我们的 REST API 接收一些 JSON 对象输入 其中某些字段要求不为空 这些可以是字符串 整数 甚至可以是其他一些类实例作为参考 我们正在尝试找到一种方法来强制这些字段不为空 而不是在 API 中进行空检查的正确方法 当前的 if
  • 为什么 Java 中的 hashCode() 可以对不同对象返回相同的值?

    引用我正在读的书中的一段话首先Java http www amazon co uk Head First Java Kathy Sierra dp 0596009208 关键是 哈希码可以相同 但不一定保证对象相等 因为使用的 哈希算法 h
  • 如何使用 UUID 生成唯一的正 Long

    我需要为我的数据库主键列生成唯一的长 ID 我以为我可以用UUID randomUUID getMostSignificantBits 但有时它也会产生一些负多头 这对我来说是个问题 是否可以从 UUID 中仅生成正长 将会有数十亿个条目
  • 在 Java 中打开现有文件并关闭它。

    是否可以在java中打开一个文件附加数据并关闭多次 例如 psuedocode class variable declaration FileWriter writer1 new FileWriter filename fn1 writer
  • JSP 作为电子邮件模板

    有没有办法发送 MIME 电子邮件 其中电子邮件正文源自 JSP 我需要使用 Javamail 发送一封电子邮件 其中包含一个表格 我认为如果我可以使用 JSP 来完成所有格式设置和布局 将会很方便 在这个线程中 Java 电子邮件模板的建
  • 在openjdk:7-jre-alpine docker上如何安装python 3.6

    直到大约一周前 我才在 java 图像上成功使用 python 3 6 脚本 如下所示 FROM openjdk 7 jre alpine RUN apk update apk upgrade apk add no cache bash a
  • EclipseLink 2.7.0 和 JPA API 2.2.0 - 签名不匹配

    当运行由maven构建的具有以下依赖项的项目时
  • 使用 spring-data-cassandra 的用户定义类型

    我希望创建如下模型 如何在 spring data cassandra 中使用用户定义的类型 email email protected cdn cgi l email protection name fname First lname L
  • Android - 保持用户登录状态

    我正在尝试使用 PHP 和 MySQLi for Android 进行登录 我不明白的是如何保持用户登录状态 我看到一个简单的教程 其中有人使用 SQLite 来保护信息 但我不知道这是否真的安全 如何保存用户信息以保持用户登录状态 谢谢
  • 线程睡眠阻止我的 Swing 应用程序执行

    我的应用程序发生的事情是有道理的 但我不知道如何修复它 以下是我的应用程序功能的简要描述 计时器窗口应显示在屏幕右下角并显示实时时间 一小时后 它应该执行一些操作 我还没有决定该操作 我面临的问题是定时器 java当我刷新实时计时器的秒数时
  • WebSocketStompClient 将无法连接到 SockJS 端点

    我正在尝试新的 从版本 4 2 开始 java STOMP 客户端支持 我的出发点是入门指南 使用 WebSocket 构建交互式 Web 应用程序 http spring io guides gs messaging stomp webs
  • 为什么 HttpServletRequest 输入流为空?

    我有这段代码 我从请求输入流读取输入并使用 JacksonMapper 转换为 POJO 它在具有 guice 支持的 jetty 7 容器中运行 Override protected void doPost HttpServletRequ
  • 如何将多部分文件从另一个服务发送到一个服务

    我有两个端点 api 它们是 uploadand 重定向 upload是我直接上传文件的地方 重定向是我接收文件并将其传递给上传并获取 JSON 响应的地方 upload 所以下面是我的代码 package com example impo
  • RecyclerView 适配器的 Kotlin 泛型

    我正在尝试编写一个通用的 recyclerview 适配器 我找到了几个例子 然而 仍然无法弄清楚如何实现通用适配器 我写的代码是 open abstract class BaseAdapter

随机推荐

  • 【前端面经】JS-如何使用 JavaScript 来判断用户设备类型?

    在 Web 开发中 有时需要针对不同的设备类型进行不同的处理 例如 对于移动设备 我们可能需要采用不同的布局或者交互方式 以提供更好的用户体验 因此 如何判断用户设备类型成为了一个重要的问题 1 使用 navigator userAgent
  • python优雅地爬虫

    申明 仅用作学习用途 不提供任何的商业价值 背景 我需要获得新闻 然后tts 在每天上班的路上可以听一下 具体的方案后期我也会做一次分享 先看我喜欢的万能的老路 获得html内容 gt python的工具库解析 获得元素中的内容 完成 好家
  • 『Newsletter丨第一期』PieCloudDB 新增自动启停、预聚集、试用规则优化、费用中心等多项功能模块...

    第一部分 PieCloudDB 最新动态 PieCloudDB 完成多个产品兼容性认证 PieCloudDB 与多家基础架构软件厂商完成产品兼容性认证 类别包括操作系统 服务器 CPU 云平台 新增 8 家生态伙伴 包括龙蜥 麒麟 中科可控
  • c语言求fibonacci数列前20,求fibonacci数列的前20个数之和

    使用数组求Fibonacci数列的前20项 要求4项一行输出 斐波那契数列通项公式 斐波那契数列指的是这样一个数列 1 1 2 3 5 8 13 21 这个数列从第三项开始 每一项都等于前两项之和 includeintmain inta 2
  • 容斥原理——经典例题(组合数学)

    一 容斥原理 就是人们为了不重复计算重叠部分 想出的一种不重复计算的方法 先来认识一下这两个符号 与 如图 蓝色的圈就是c1c2 红色的圈围起来的就是c1c2 二 例题 组合数学 1 题目 1 1 题目描述 八是个很有趣的数字啊 八 发 八
  • Centos nginx配置文档

    1 安装nginx yum install nginx 2 Nginx常用命令 查看版本 nginx v 启动 nginx c etc nginx nginx conf 重新加载配置 nginx s reload 停止 nginx s st
  • Bat批处理使用ren批量重命名文件,比如批量去掉文件名称的前4位

    从手机下导入一批照片到电脑 照片开头都是以IMG 开头 甚是烦 使用ren可以批量去掉IMG 开头的几个字符 参考如下 去掉文件名称的最前面4位 去掉文件名称的最后5位 去掉的5位包括 jpg这四个后缀 echo off Deep Lee
  • OCR文字检测主要算法

    转载 https www mayi888 com archives 60604 文字检测是文字识别过程中的一个非常重要的环节 文字检测的主要目标是将图片中的文字区域位置检测出来 以便于进行后面的文字识别 只有找到了文本所在区域 才能对其内容
  • 西门子 PLC S7单边通信

    PLC通信 1 组态 编程 1 打开博途软件 创建新项目 命名为 通信 2 添加新设备 命名为A 这里选择的是CPU1211C 版本V4 2 3 CPU属性设置 启用系统存储器字节和时钟存储器字节 4 以太网地址设置 IP地址设为 192
  • 一文说明白SMC继电器的三种模式:迟滞模式,窗口模式,报警模式

    阅读时间5分钟 有不少同学表示 不理解迟滞模式 窗口模式 报警模式 这里花点儿时间说明一下 这三种模式按照难易程度 1 报警模式 这种方式顾名思义 到压力报警 回到正常范围 报警消除 简单易懂 不过 如果我们需要的压力是0 7MPa 那么我
  • Java坑人面试题系列: 变量声明(中级难度)

    作用域规则与变量覆盖面试题 Java Magazine上面有一个专门坑人的面试题系列 https blogs oracle com javamagazine quiz 2 这些问题的设计宗旨 主要是测试面试者对Java语言的了解程度 而不是
  • 华为OD -单词接龙(Python)

    单词接龙 题目描述 单词接龙的规则是 可用于接龙的单词 首字母必须要与前一个单词的尾字母相同 当存在多个首字母相同的单词时 取长度最长的单词 如果长度也相等 则取字典序最小的单词 已经参与接龙的单词不能重复使用 现给定一组全部由小写字母组成
  • vue+element-ui el-descriptions 详情渲染组件二次封装(Vue项目)

    目录 1 需求 2 想要的效果就是由图一变成图二 编辑 3 组件集成了以下功能 4 参数配置 示例代码 参数说明 5 组件 6 页面使用 1 需求 一般后台管理系统 通常页面都有增删改查 而查不外乎就是渲染新增 修改的数据 由输入框变成输入
  • Oracle 数据库查看锁表的语句和解锁的方法

    一 查看锁表语句 SELECT sess sid sess serial lo oracle username 登陆账号名称 lo os user name 登录电脑名称 ao object name 被锁表名 lo locked mode
  • 【Vulnhub】之symfonos1

    一 部署方法 在官网上下载靶机ova环境 https download vulnhub com symfonos symfonos1 7z 使用VMware搭建靶机环境 攻击机使用VMware上搭建的kali 靶机和攻击机之间使用NAT模式
  • oracle impdp无法打开日志文件,oracle expdp导入时 提示“ORA-39002: 操作无效 ORA-39070: 无法打开日志文件 ”...

    oracle impdp导入时 提示 OpenCurlyDoubleQuote ORA 39002 colon 操作无效 ORA 39070 colon 无法打开日志文件 第一步 首先使用DBA权限的用户创建directory 我使用sys
  • ‘git‘不是内部或外部命令,也不是可运行的程序或批处理文件。

    一 出现问题 git 不是内部或外部命令 也不是可运行的程序或批处理文件 出现这个问题主要是git的环境变量没有设置 二 解决问题 首先右键我的电脑点击属性 在点击高级系统设置 点击环境变量 在下面这栏点击path设置环境变量 添加这三个环
  • 【人工智能】感知器算法的设计实现(QDU)

    人工智能 Astar算法求解8数码问题 QDU 人工智能 利用 搜索的博弈树算法编写一字棋游戏 QDU 人工智能 Fisher 线性分类器的设计与实现 QDU 人工智能 感知器算法的设计实现 QDU 人工智能 SVM 分类器的设计与应用 Q
  • Hive的数据类型

    Hive支持的数据类型如下 原生类型 TINYINT SMALLINT INT BIGINT BOOLEAN FLOAT DOUBLE STRING BINARY Hive 0 8 0以上才可用 TIMESTAMP Hive 0 8 0以上
  • 04-SpringBoot集成Nebula Graph

    SpringBoot集成Nebula 建议模块 在这里给大家推荐一种方式 每引入一种新的技术 建议新建一个模块 来适配这种技术 对外提供接口 在调用的地方应用就可以 不用搞的到处都是 防止如果后续替换这种技术 还要到处修改 这样的话 只需要