首页 > 其他分享 >License的生成,安装,验证

License的生成,安装,验证

时间:2024-08-02 17:28:44浏览次数:11  
标签:keyBytes String License 验证 System param 生成 new import

写这篇的原因:

最近有个项目需要交付给第三方,要使用证书进行验证,不验证就不让他们用

license的流程:

生成:

  • license许可证应包含必要的信息,如许可证ID、用户ID、产品ID、有效期、许可类型(如单用户、多用户、永久、试用等)。
  • 加密算法:使用非对称加密算法(如RSA)生成公钥和私钥。私钥用于签名许可证,公钥用于验证许可证的签名。
  • 签名:使用私钥对许可证的内容进行数字签名,确保许可证的完整性和防篡改性。

导入安装:

  • 用户手动导入许可证,提供一个许可证导入接口(即上传文件并安装)

验证:

  • 定期或在特定事件(如使用某些受限功能)时,验证许可证的合法性。
  • 或在拦截器中添加验证的逻辑,不需要验证的接口放行即可

license的生成和验证

1.使用工具生成秘钥对(公钥和私钥)

我是在jdk/bin目录下使用keytool生成的,需要的命令如下:

  • 创建密钥库(包含公钥、私钥)
  • keytool -genkeypair -alias avc-privatekey -keysize 1024 -keystore private-keystore.p12 -storetype PKCS12 -dname "CN=XX, OU=WONSEC, O=WONSEC, L=HZ, ST=ZJ, C=CN"
  • 导出证书(证书中包含公钥)
  • keytool -exportcert -alias "avc-privatekey" -keystore private-keystore.p12 -file "certfile.cer"
  • 导入证书(生成新的密钥库,其中只包含公钥)
  • keytool -import -alias "avc-publickey" -file "certfile.cer" -keystore "public-keystore.p12" -storetype PKCS12

2.获取硬件的序列号等

3.根据序列号和秘钥,私钥生成证书

4.证书上传验证

相关代码如下:

获取序列号的类

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wonsec.cc.core.model.LicenseExtraParam;
import com.wonsec.cc.core.service.AServerInfos;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.security.MessageDigest;
import java.util.Base64;

@Service
public class UserServerInfo {

    @Value("${license.key}")
    private  String key;

    public String ServerInfo() throws Exception {
        System.out.println("key = " + key);
        LicenseExtraParam serverInfos = AServerInfos.getServer("").getServerInfos();

        //对象序列化为json
        String jsonString = serverInfos.toJsonString();
        System.out.println("原始数据 = " + jsonString);
        //加密
        String encryptedJson = encrypt(jsonString);
        System.out.println("加密后 = " + encryptedJson);
        // 解密
        String decryptedJson = decrypt(encryptedJson);
        System.out.println("解密后 = " + decryptedJson);
        // 比较解密后的字符串与原始字符串
        if (jsonString.equals(decryptedJson)) {
            System.out.println("解密后的字符串与原始字符串相同");
        } else {
            System.out.println("解密后的字符串与原始字符串不同");
        }

        // 断言
        assert jsonString.equals(decryptedJson) : "解密后的字符串与原始字符串不匹配";

        // 反序列化为对象
        ObjectMapper mapper = new ObjectMapper();
        LicenseExtraParam licenseParam = null;
        licenseParam = mapper.readValue(decryptedJson, LicenseExtraParam.class);
        // 标记为null的字段需要特殊处理
        if ("null".equals(licenseParam.getRegisterAmount())) {
            licenseParam.setRegisterAmount(null);
        }
        System.out.println("licenseParam = " + licenseParam);
        return encryptedJson;
    }

    public   String encrypt(String json) throws Exception {
        byte[] keyBytes = key.getBytes();
        MessageDigest sha = MessageDigest.getInstance("SHA-256");
        keyBytes = sha.digest(keyBytes);
        keyBytes = java.util.Arrays.copyOf(keyBytes, 16);
        SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");

        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        byte[] encryptedBytes = cipher.doFinal(json.getBytes());
        return Base64.getEncoder().encodeToString(encryptedBytes);
    }

    public String decrypt(String encryptedJson) throws Exception {
        byte[] keyBytes = key.getBytes();
        MessageDigest sha = MessageDigest.getInstance("SHA-256");
        keyBytes = sha.digest(keyBytes);
        keyBytes = java.util.Arrays.copyOf(keyBytes, 16);
        SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");

        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        byte[] encryptedBytes = Base64.getDecoder().decode(encryptedJson);
        byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
        return new String(decryptedBytes);
    }
}

controller調用代碼如下: 

@RestController
@RequestMapping("/license")
public class SeverInfoController {
    @Resource
    private UserServerInfo userServerInfo;
    @ResponseBody
    @RequestMapping(value = "/severInfo", method = RequestMethod.POST)
    public Map<String,Object> severInfo() throws Exception {
        JSONObject jsonObject = new JSONObject();
        String value = userServerInfo.ServerInfo();
        jsonObject.put("status","200");
        jsonObject.put("needValue",value);
        return jsonObject;
    }
}

创建License的类如下:

public class Main {
    public static void main(String[] args) {
//        if (args.length == 1 && args[0].equals("-h")) {
//            System.out.println("用法: java YourProgramName -k key -i IssuedTime -e ExpiryTime");
//            System.out.println("参数说明:");
//            System.out.println("-k: 许可证密钥");
//            System.out.println("-i: 许可证生效时间(格式: yyyy-MM-dd HH:mm:ss)");
//            System.out.println("-e: 许可证过期时间(格式: yyyy-MM-dd HH:mm:ss)");
//            System.out.println("示例: java YourProgramName -k ABC123 -i \"2024-05-09 12:00:00\" -e \"2024-05-10 12:00:00\"");
//        } else {
        // 处理其他参数
        //key是上一步接口生成的序列号加密码
        String key = "OKMn+Ljh9pMWlb5a4obb9axCwCNAkOzjlHJ3r cxvvdfdCFskgckwY/7RS4gV0BaMz2ySKRu09UDKh+jNHQ4Uy7I4GskVhSfUtC/fQSqcjEMmsNOpPCmxnVWVT7oMQmpeXYR9VkkebaD+1pjx114O+8";
        String IssuedTime = "2024-07-15 09:40:00";
        String ExpiryTime = "2024-07-22 17:30:00";

        // 判断传入参数
//            for (int i = 0; i < args.length; i++) {
//                if (args[i].equals("-k") && i + 1 < args.length) {
//                    key = args[i + 1];
//                } else if (args[i].equals("-i") && i + 1 < args.length) {
//                    IssuedTime = args[i + 1];
//                } else if (args[i].equals("-e") && i + 1 < args.length) {
//                    ExpiryTime = args[i + 1];
//                }
//            }

        if (key.isEmpty() || IssuedTime.isEmpty() || ExpiryTime.isEmpty()) {
            System.out.println("参数不完整。请使用 '-h' 获取帮助信息。");
        } else {
            Create create = new Create();
            try {
                create.Create(key, IssuedTime, ExpiryTime);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
//        }
    }
}

Create类如下:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.wonsec.cc.core.model.LicenseCreatorParam;
import com.wonsec.cc.core.model.LicenseExtraParam;
import com.wonsec.cc.core.service.AServerInfos;
import com.wonsec.cc.core.utils.CommonUtils;
import com.wonsec.cc.creator.config.LicenseCreatorProperties;
import com.wonsec.cc.creator.service.LicenseCreatorService;
import com.wonsec.cc.verify.Sevice.UserServerInfo;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Base64;
import java.util.TimeZone;

/**
 * @Author: WangYao
 * @description:
 * @date: 2024-05-08 10:36
 */
public class Create {

    private static final String key = "mySecretKey";
    private LicenseCreatorService creatorService = new LicenseCreatorService();


    private LicenseCreatorProperties properties = new LicenseCreatorProperties();

    public void Create(String key,String IssuedTime,String ExpiryTime) throws Exception {

        // 解密
        String decryptedJson = decrypt(key);
        // 反序列化为对象
        ObjectMapper mapper = new ObjectMapper();
        LicenseExtraParam licenseParam = null;
        licenseParam = mapper.readValue(decryptedJson, LicenseExtraParam.class);
        // 设置需要校验那些硬件
        licenseParam.setCpuCheck(true);
        licenseParam.setMacCheck(true);
        licenseParam.setIpCheck(true);
        licenseParam.setBoardCheck(true);

        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        dateFormat.setTimeZone(TimeZone.getTimeZone("GMT+8"));
        // 如果没有人为的指定lic要生成的位置,则程序自动处理
        LicenseCreatorParam param = new LicenseCreatorParam();
        param.setSubject("license");
        param.setPrivateAlias("privateKeys");
        param.setKeyPass("123456a");
        param.setStorePass("123456a");
        param.setPrivateKeysStorePath("/privateKeys.store");
        // param.setIssuedTime(dateFormat.parse("2024-03-01 08:30:00"));
        // param.setExpiryTime(dateFormat.parse("2024-05-09 14:38:00"));
        param.setIssuedTime(dateFormat.parse(IssuedTime));
        param.setExpiryTime(dateFormat.parse(ExpiryTime));
        param.setDescription("系统软件许可证书");

        // 获取当前机器证书
        // LicenseExtraParam serverInfos = AServerInfos.getServer("").getServerInfos();
        LicenseExtraParam serverInfos = licenseParam;
        param.setLicenseCheck(serverInfos);
        if (CommonUtils.isEmpty(param.getLicensePath())) {
            // 设置格式
            SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
            String tempPath = properties.getTempPath();
            if (tempPath == null || "".equals(tempPath)) {
                // 如果默认临时文件等于空的话,就获取当前服务执行的路径
                tempPath = AServerInfos.getServerTempPath();
            }
            // 根据时间戳,命名lic文件
            String licDir = tempPath + "/lic-files/" + format.format(System.currentTimeMillis());
            File file = new File(licDir);
            if (!file.exists()) {
                if (!file.mkdirs()) {
                    throw new RuntimeException("创建目录" + licDir + ",失败,请检查是是否有创建目录的权限或者手动进行创建!");
                }
            }
            /**统一下路径分隔符*/
            param.setLicensePath(licDir.replace("\\", "/") + "/license.lic");
            creatorService.generateLicense(param);
        }
    }

    public void LicenseCreate(String key,String IssuedTime,String ExpiryTime) throws Exception {

        // 解密
        String decryptedJson = decrypt(key);
        // 反序列化为对象
        ObjectMapper mapper = new ObjectMapper();
        LicenseExtraParam licenseParam = null;
        licenseParam = mapper.readValue(decryptedJson, LicenseExtraParam.class);
        // 设置需要校验那些硬件
        licenseParam.setCpuCheck(true);
        licenseParam.setMacCheck(true);
        licenseParam.setIpCheck(true);
        licenseParam.setBoardCheck(true);

        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        dateFormat.setTimeZone(TimeZone.getTimeZone("GMT+8"));
        // 如果没有人为的指定lic要生成的位置,则程序自动处理
        LicenseCreatorParam param = new LicenseCreatorParam();
        param.setSubject("license");
        param.setPrivateAlias("privateKeys");
        param.setKeyPass("123456a");
        param.setStorePass("123456a");
        param.setPrivateKeysStorePath("/privateKeys.store");
        // param.setIssuedTime(dateFormat.parse("2024-03-01 08:30:00"));
        // param.setExpiryTime(dateFormat.parse("2024-05-09 14:38:00"));
        param.setIssuedTime(dateFormat.parse(IssuedTime));
        param.setExpiryTime(dateFormat.parse(ExpiryTime));
        param.setDescription("系统软件许可证书");

        // 获取当前机器证书
        // LicenseExtraParam serverInfos = AServerInfos.getServer("").getServerInfos();
        LicenseExtraParam serverInfos = licenseParam;
        param.setLicenseCheck(serverInfos);
        if (CommonUtils.isEmpty(param.getLicensePath())) {
            // 设置格式
            SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
            String tempPath = properties.getTempPath();
            if (tempPath == null || "".equals(tempPath)) {
                // 如果默认临时文件等于空的话,就获取当前服务执行的路径
                tempPath = AServerInfos.getServerTempPath();
            }
            // 根据时间戳,命名lic文件
            String licDir = tempPath + "/lic-files/" + format.format(System.currentTimeMillis());
            File file = new File(licDir);
            if (!file.exists()) {
                if (!file.mkdirs()) {
                    throw new RuntimeException("创建目录" + licDir + ",失败,请检查是是否有创建目录的权限或者手动进行创建!");
                }
            }
            /**统一下路径分隔符*/
            param.setLicensePath(licDir.replace("\\", "/") + "/license.lic");
            creatorService.generateLicense(param);
        }
    }

    public static String decrypt(String encryptedJson) throws Exception {
//        byte[] keyBytes = key.getBytes();
//        MessageDigest sha = MessageDigest.getInstance("SHA-256");
//        keyBytes = sha.digest(keyBytes);
//        keyBytes = Arrays.copyOf(keyBytes, 16);
//        SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");
        Cipher cipher = Cipher.getInstance("AES");
//        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
//        cipher.init(Cipher.DECRYPT_MODE, secretKey);
//        byte[] encryptedBytes = Base64.getDecoder().decode(encryptedJson);
//        byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
//        return new String(decryptedBytes);
        byte[] keyBytes = key.getBytes();
        MessageDigest sha = MessageDigest.getInstance("SHA-256");
        keyBytes = sha.digest(keyBytes);
        keyBytes = java.util.Arrays.copyOf(keyBytes, 16);
        SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");

        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        byte[] encryptedBytes = Base64.getDecoder().decode(encryptedJson);
        byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
        return new String(decryptedBytes);
    }
}

证书的上传和验证接口如下:

import com.alibaba.fastjson.JSONObject;
import com.mm.cc.Utils.FileUtils;
import com.mm.cc.verify.Sevice.VerifyMain;
import com.mm.cc.verify.Sevice.VerifyValue;
import com.mm.cc.verify.config.LicenseVerifyProperties;
import com.mm.cc.verify.listener.LicenseVerifyInstallListener;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;


@RestController
@RequestMapping("/license")
public class UploadLicenseFile {
    @Value("${license.licenseFilePath}")
    private String licenseFilePath;
    @Resource
    private VerifyValue verifyValue;
    @ResponseBody
    @RequestMapping(value = "/uploadLicenseFile", method = RequestMethod.POST, produces = "application/json;charset=utf-8")
    public JSONObject uploadLicenseFile(@RequestParam("file") MultipartFile file, HttpServletRequest request) {
        LicenseVerifyProperties licenseVerifyProperties = verifyValue.licenseVerifyProperties();
        JSONObject jsonObject=new JSONObject();
        //获取原始文件名
        String fileName = file.getOriginalFilename();
        if (fileName == null || "".equals(fileName)) {
            jsonObject.put("status",303);
            jsonObject.put("msg","上传证书不能为空");
            return jsonObject;
        }
        //在此判断文件类型是否为.lic
        String fileExtension = getFileSuffix(fileName);
        if (!fileExtension.equals(".lic")) {
            // 文件类型不正确,返回错误信息
            jsonObject.put("status",305);
            jsonObject.put("msg","证书格式不正确");
            return jsonObject;
        }
//        if (!fileName.equals("license.lic")) {
//            // 文件类型不正确,返回错误信息
//            jsonObject.put("status",305);
//            jsonObject.put("msg","证书名称不正确");
//            return jsonObject;
//        }

        SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
//        String filePath = licenseFilePath + "/license/" + format.format(System.currentTimeMillis())+"/";
        String filePath = licenseFilePath + format.format(System.currentTimeMillis())+"/";
        try {
            FileUtils.upload(file.getBytes(), filePath, fileName);
        } catch (Exception e) {
            e.printStackTrace();
        }
        boolean b= LicenseVerifyInstallListener.install1(licenseVerifyProperties);
//        boolean b = verifyMain.installListener();
        if (b) {
            jsonObject.put("status",200);
            jsonObject.put("msg","证书上传并安装成功");
            return jsonObject;
        } else {
            jsonObject.put("status",500);
            jsonObject.put("msg","证书安装失败");
            return jsonObject;
        }

    }

    private String getFileSuffix(String fileName) {
        int dotIndex = fileName.lastIndexOf(".");
        if (dotIndex < 0) {
            return "";
        }
        return fileName.substring(dotIndex);
    }
}

用到的验证类:

import com.mm.cc.core.model.LicenseResult;
import com.mm.cc.core.model.LicenseVerifyManager;
import com.mm.cc.core.utils.CommonUtils;
import com.mm.cc.verify.config.LicenseVerifyProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;


public class LicenseVerifyInstallListener {

//    @Autowired
//    LicenseVerifyProperties licenseVerifyProperties;
    public LicenseVerifyProperties licenseVerifyProperties;
    private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
    private ScheduledFuture<?> scheduledFuture;


    // 启动定时任务
    public void startTimer() {
        scheduledFuture = scheduler.scheduleAtFixedRate(this::timer, 0, 5, TimeUnit.SECONDS);
    }
    // 停止定时任务
    public void stopTimer() {
        if (scheduledFuture != null) {
            scheduledFuture.cancel(false);
        }
    }
    /**
     * 文件唯一身份标识 == 相当于人类的指纹一样
     */
    private static String md5 = "";
    private static boolean isLoad = false;

    public static void LicenseVerifyInstall(LicenseVerifyProperties licenseVerifyProperties) {
        new LicenseVerifyInstallListener(licenseVerifyProperties);
    }

    public LicenseVerifyInstallListener(LicenseVerifyProperties licenseVerifyProperties) {
        // startTimer();
        this.licenseVerifyProperties = licenseVerifyProperties;
        System.out.println("licenseVerifyProperties.getLicensePath() = " + licenseVerifyProperties.getLicensePath());
        if (CommonUtils.isNotEmpty(licenseVerifyProperties.getLicensePath())) {
            install();
            try {
                String readMd5 = getMd5(licenseVerifyProperties.getLicensePath());
                isLoad = true;
                if (LicenseVerifyInstallListener.md5 == null || "".equals(LicenseVerifyInstallListener.md5)) {
                    LicenseVerifyInstallListener.md5 = readMd5;
                }
            } catch (Exception e) {

            }
        }
    }


    /**
     * 5秒检测一次,不能太快也不能太慢
     */
    protected void timer()  {
        if (!isLoad) {
            return;
        }
        String readMd5 = null;
        try {
            readMd5 = getMd5(licenseVerifyProperties.getLicensePath());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        // 不相等,说明lic变化了
        if (!readMd5.equals(LicenseVerifyInstallListener.md5)) {
            install();
            LicenseVerifyInstallListener.md5 = readMd5;
        }
    }

    private void install() {
        System.out.println("++++++++ 开始安装证书 ++++++++");
        LicenseVerifyManager licenseVerifyManager = new LicenseVerifyManager();
        /** 走定义校验证书并安装 */
        LicenseResult result = licenseVerifyManager.install(licenseVerifyProperties.getVerifyParam());
        if (result.getResult()) {
            System.out.println("++++++++ 证书安装成功 ++++++++");
        } else {
            System.out.println("++++++++ 证书安装失败 ++++++++");
        }
    }

    public static boolean install1(LicenseVerifyProperties licenseVerifyProperties) {
        System.out.println("licenseVerifyProperties = " + licenseVerifyProperties);
        System.out.println("++++++++ 开始安装证书 ++++++++");
        LicenseVerifyManager licenseVerifyManager = new LicenseVerifyManager();
        /** 走定义校验证书并安装 */
        LicenseResult result = licenseVerifyManager.install(licenseVerifyProperties.getVerifyParam());
        if (result.getResult()) {
            System.out.println("++++++++ 证书安装成功 ++++++++");
            return true;
        } else {
            System.out.println("++++++++ 证书安装失败 ++++++++");
            return false;
        }
    }

    /**
     * <p>获取文件的md5</p>
     */
    public String getMd5(String filePath) throws Exception {
        File file;
        String md5 = "";
        try {
            file = new File(filePath);
            if (file.exists()) {
                FileInputStream is = new FileInputStream(file);
                byte[] data = new byte[is.available()];
                is.read(data);
                md5 = calculateMD5(data);
                is.close();
            }
        } catch (FileNotFoundException e) {

        }
        return md5;
    }

    public static String calculateMD5(byte[] data) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] hashBytes = md.digest(data);

            StringBuilder hexString = new StringBuilder();
            for (byte b : hashBytes) {
                String hex = Integer.toHexString(0xff & b);
                if (hex.length() == 1) {
                    hexString.append('0');
                }
                hexString.append(hex);
            }

            return hexString.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace(); // 处理异常,例如打印错误信息
            return null;
        }
    }

}

还有一些涉及的类,有点多,想要的可以私信我

标签:keyBytes,String,License,验证,System,param,生成,new,import
From: https://blog.csdn.net/smokeblue/article/details/140522327

相关文章

  • .net项目使用Docker部署(包括解决后台验证码,部署后不显示的问题)
    Vue部署到Docker参考文档:手把手教你用Docker部署Vue3项目_docker部署vue3项目-CSDN博客参考文档:dockerfile部署前端vue项目_vuedockerfile-CSDN博客nginx文档:使用docker安装nginx-静以修身俭以养德-博客园(cnblogs.com)结合使用了两个文档的方法和DockerFIle区别......
  • springboot+vue前后端分离项目-项目搭建15-集成JWT token权限验证
    1.对之前的代码改造,之前将user存储到sessionStorage,改成存储到localStorage,全局搜索修改 之前Result.code等于0代表success,改成200代表success,vue文件全局搜索修改一、前端部分1.改造request.js,登录时将user已经存储到localStorage里,这里将user获取到,将user里的token放到......
  • 代码随想录day17 || 654 最大二叉树,617 合并二叉树,700 二叉搜索树搜索,98 验证二叉搜索
    645最大二叉树funcconstructMaximumBinaryTree(nums[]int)*TreeNode{ //思路,算法思路基本等同于通过中序前序构造二叉树 //1,取最大值作为根节点 //2,切割数组 //3,递归左右子树 iflen(nums)==0{ returnnil } //切割数组取最大值 max,left,right:=......
  • day16 Java基础——JavaDoc生成文档
    day16Java基础——JavaDoc生成文档目录day16Java基础——JavaDoc生成文档1.什么是JavaDoc2.生成JavaDoc2.1通过命令行生成JavaDoc2.2使用IDEA生成JavaDoc1.什么是JavaDocJavaDoc是一种标准的、用于生成Java代码API文档的工具。它通过在Java源代码中特定的......
  • 随机生成10个整数(1-100的范围)保存到数组,并倒序打印以及求平均值、求最大值和最大值
    1publicclassshuzu19{2//编写一个main方法3publicstaticvoidmain(String[]args){4/*5随机生成10个整数(1-100的范围)保存到数组6并倒序打印以及求平均值、求最大值和最大值的下标、7并查找里面是否有88......
  • SourceGenerator 生成db to class代码优化结果记录
    优化上一次实验代码写的较为随意,本次穷尽所学,优化了一把,不过果然还是没比过Dapperaot,虽然没使用Interceptor,但理论上其优化不该有这么大差距知识差距不少呀,都看不懂Dapperaot利用了什么姿势领先,有大神们能教教吗?优化点减少类型判断提前做类型判断,并在生成时利用......
  • SQL Server 将查询的结果生成insert语句
    思路参考https://www.cnblogs.com/LeiYang5237/p/8549621.html总结:将查询结果插入新表,然后生成脚本自己操作过程:1、数据库表TEST初始数据2、将包含abc的数据查询,并插入到新表TEST2中3、新表TEST2中的数据4、最后生成脚本......
  • 解密编程的八大法宝(四)(附二分查找、分治法和图论算法(深度和广度优先搜索、最短路径、最
    算法题中常见的几大解题方法有以下几种::暴力枚举法(BruteForce):这是最基本的解题方法,直接尝试所有可能的组合或排列来找到答案。这种方法适用于问题规模较小的情况,但在大多数情况下效率不高。贪心算法(GreedyAlgorithm):贪心算法在每一步都选择当前看起来最优的解,希望最终能......
  • clion 《cmake自定义静态库后,生成的exe无法运行》
    背景项目生成lib引入,在生成exe过程中无法正常运行处理办法让链接器静态链接GCC和C++标准库set(CMAKE_EXE_LINKER_FLAGS"-static-libgcc-static-libstdc++")主CMakeLists.txtcmake_minimum_required(VERSION3.28)project(speech)#编译版本set(CMAKE_CXX_STANDAR......
  • vue生成初始化名字相近的变量并放到数组中
    项目上有一个需求,页面上有50、60个数据变量,是依次排序递增的变量,中间有个别变量用不到,不想把这些变量直接定义在data(){}内。直接上代码1.在mounted(){},大括号内定义并初始化变量1this.yx_1hddj_arr=[];2this.yx_2hddj_arr=[];3this.yx_3hddj_arr......