jbase实现业务脚本化

news2024/11/25 0:28:14

经过晚上和早上的努力,终于补上框架最后一块了,业务脚本侦听变化后自动编译jar包和调用,实现维护成本低,开发效率高的框架的基本体系。

实现自动编译jar包的类

package appcode;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.nio.file.Paths;
import java.util.concurrent.ConcurrentHashMap;
import java.util.*;
import java.io.*;
import org.apache.commons.io.FileUtils;
import java.nio.charset.StandardCharsets;
import java.nio.charset.*;

public class AutoBuild {
    /// <summary>
    /// 缓存路径和类型,允许多线程读一个线程写
    /// </summary>
    private static ConcurrentHashMap<String, Boolean> Building = new ConcurrentHashMap<>();

    /// <summary>
    /// 编译指定路径的java代码
    /// </summary>
    /// <param name="basePath">根路径</param>
    /// <param name="codepath">类代码路径</param>
    /// <param name="proname">工程名称,不带后缀的</param>
    /// <param name="standprofilepath">标准工程文件全路径</param>
    /// <returns>返回空成功,非空就是失败原因</returns>
    public static String Build(String basePath,String codepath, String proname, String standprofilepath)
    {
        Process proc = null;
        try
        {
            //有编译的退出
            if (Building.containsKey(codepath))
            {
                System.out.println(codepath+"已经有进程在编译了,退出本次编译!");
                return "";
            }
            try
            {
                if (!Building.containsKey(codepath))
                {
                    AutoBuild.HashTryAdd(Building, codepath, true);
                }
            }
            catch (Exception ex)
            {
                System.out.println("编译并发"+ex.getMessage());
            }
            //编译临时总目录
            String buildPath = Paths.get(basePath, "AutoBuildTmp").toString();
            File directory = new File(buildPath);
            //没有编译的临时目录就创建
            if (!directory.exists()) {
                directory.mkdirs();
            }
            //构建项目编译文件夹
            String proBuildPath = Paths.get(buildPath, proname).toString();
            File directoryPro = new File(proBuildPath);
            //没有编译的临时目录就创建
            if (!directoryPro.exists()) {
                directoryPro.mkdirs();
            }
            File fi = new File(codepath);
            //编译目录类全名
            String clsFullName = Paths.get(proBuildPath, fi.getName()).toString();
            System.out.println("拷贝:" + codepath + "到:"+ clsFullName);
            List<String> lines = FileUtils.readLines(fi, "UTF-8");
            StringBuilder sbNewCode=new StringBuilder();
            String jarRootPath=proBuildPath;
            System.out.println("包名称:" + proname);
            String [] arr=proname.split("\\.");
            String pakName="";
            if(arr.length>1)
            {
                for(int p=0;p<arr.length-1;p++)
                {
                    jarRootPath=Paths.get(jarRootPath,arr[p]).toString();
                    //创建jar包目录结构
                    File directoryProJarChild = new File(jarRootPath);
                    //没有编译的临时目录就创建
                    if (!directoryProJarChild.exists()) {
                        directoryProJarChild.mkdirs();
                    }
                    if(pakName=="")
                    {
                        pakName=arr[p];
                    }
                    else
                    {
                        pakName+="."+arr[p];
                    }
                }
            }
            sbNewCode.append("package "+pakName+";"+System.lineSeparator());
            for (String line : lines) {
                sbNewCode.append(line+System.lineSeparator());
            }
            WriteText2File(clsFullName,sbNewCode.toString());
            //复制类代码
            //copyFile(new File(codepath), new File(clsFullName));
            String cmmand = "javac";
            StringBuilder retsb = new StringBuilder();
            //得到javac编译命令串
            String cmdStr=GetJavacStr(basePath,standprofilepath,fi.getName());
            System.out.println("编译命令:" + cmdStr);
            System.out.println("运行路径:" + directoryPro);
            // 创建进程并执行命令
            Process process = Runtime.getRuntime().exec(cmdStr,null,directoryPro);
            // 获取命令行程序的输出结果
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;
            while ((line = reader.readLine()) != null) {
                retsb.append(line);
            }
            // 等待命令行程序执行完毕
            int exitCode=process.waitFor();
            // 关闭资源
            reader.close();
            System.out.println("编译返回:" + exitCode);
            //编译完成
            if (exitCode == 0)
            {
                // 获取目录中的所有文件和子目录
                File[] files = directoryPro.listFiles();
                // 遍历文件和子目录
                for (File file : files) {
                    if (!file.isDirectory()) {
                        if (file.getName().endsWith(".class")) {
                            copyFile(new File(file.toString()),new File(Paths.get(jarRootPath,file.getName()).toString()));
                        }
                    }
                }
                String pakStr="jar cf "+proname+".jar"+" "+arr[0];
                System.out.println("打包命令:" + pakStr);
                System.out.println("打包运行路径:" + directoryPro);
                //打包jar包
                Process processPak = Runtime.getRuntime().exec(pakStr,null,directoryPro);
                // 等待命令行程序执行完毕
                int exitCodePak=processPak.waitFor();
                System.out.println("打包返回:" + exitCodePak);
                if (exitCodePak == 0)
                {
                    String jarOutPath=Paths.get(proBuildPath,proname+".jar").toString();
                    String jarBinPath=Paths.get(basePath,"BinAshx",proname+".jar").toString();
                    System.out.println("从:" + jarOutPath+"拷贝到:"+jarBinPath);
                    //拷贝生成的jar包到BinAshx
                    copyFile(new File(jarOutPath), new File(jarBinPath));
                }
                //删除源文件
                //DeleteFile(new File(proBuildPath));
                return "";
            }
            String retstr = retsb.toString();
            return retstr;
        }
        catch (Exception ex)
        {
            return ex.getMessage();
        }
        finally
        {
            if (Building.containsKey(codepath))
            {
                Building.remove(codepath);
            }
        }
    }

    /// <summary>
    /// 解决多线程写并发
    /// </summary>
    /// <param name="hs"></param>
    /// <param name="key"></param>
    /// <param name="value"></param>
    public static void HashTryAdd(ConcurrentHashMap<String, Boolean> hs, String key, Boolean value)
    {
        try
        {
            //更新类型
            if (!hs.containsKey(key))
            {
                hs.put(key, value);
            }
        }
        catch (Exception ex)
        {
            System.out.println("并发编译捕获的正常日志,忽略"+ex.getMessage());
            //更新类型
            if (!hs.containsKey(key))
            {
                hs.put(key, value);
            }
        }
    }

    ///拷贝文件
    public static void copyFile(File srcFile, File destFile) {
        //判断原文件是否存在
        if (!srcFile.exists()) {
            throw new IllegalArgumentException("源文件:" + srcFile + "不存在!");
        }
        //判断原文件是否为一个文件
        if (!srcFile.isFile()) {
            throw new IllegalArgumentException(srcFile + "不是一个文件!");
        }
        try {
            FileInputStream in = new FileInputStream(srcFile);
            FileOutputStream out = new FileOutputStream(destFile);
            /**
             * 读取原文件,以字节流的形式读到byte数组,1024个字节=1KB
             * 循环读取
             * in.read()读到bytes数组中,位置从0-bytes.length
             */
            byte[] bytes = new byte[10 * 1024];
            int b;  //b为读取到的字节长度
            while ((b = in.read(bytes, 0, bytes.length)) != -1) {
                //写入
                out.write(bytes, 0, b);
                out.flush();
            }
            //关闭
            in.close();
            out.close();
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }

    ///删除文件和目录
    public static void DeleteFile(File file){
        //判断文件不为null或文件目录存在
        if (file == null || !file.exists()){
            return;
        }
        //取得这个目录下的所有子文件对象
        File[] files = file.listFiles();
        //遍历该目录下的文件对象
        for (File f: files){
            //判断子目录是否存在子目录,如果是文件则删除
            if (f.isDirectory()){
                DeleteFile(f);
            }else {
                f.delete();
            }
        }
    }

    ///得到javac编译命令
    ///basePath:根地址
    ///standprofilepath:依赖jar包工程地址
    ///javaName:java类文件名称
    private static String GetJavacStr(String basePath,String standprofilepath,String javaName)
    {
        String retStr="javac -encoding UTF-8 -classpath ";
        try {
            //判断配置是否存在
            File file = new File(standprofilepath);
            if (!file.exists()) {
                System.out.println(standprofilepath + "文件不存在,请确认!");
                return "";
            }
            //解析xml
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document document = builder.parse(file);
            // 获得根节点
            Element rootElement = document.getDocumentElement();
            // 获得根节点下的所有子节点
            NodeList students = rootElement.getChildNodes();
            String classPath="";
            for (int i = 0; i < students.getLength(); i++) {
                // 由于节点多种类型,而一般我们需要处理的是元素节点
                Node childNode = students.item(i);
                // 元素节点就是非空的子节点,也就是还有孩子的子节点
                if (childNode.getNodeType() == Node.ELEMENT_NODE) {
                    Element childElement = (Element) childNode;
                    //不是对象配置元素就忽略
                    if (childElement.getNodeName() != "orderEntry") {
                        continue;
                    }
                    //解析得到包名
                    String name = childElement.getAttribute("name");
                    String oneJarPath=Paths.get(basePath,name+".jar").toString();
                    if(classPath=="")
                    {
                        classPath=oneJarPath;
                    }
                    else
                    {
                        classPath+=";"+oneJarPath;
                    }
                }
            }
            retStr+=classPath+" "+javaName;
            return retStr;
        }
        catch (Exception ex) {
            System.out.println(standprofilepath + ex.getMessage());
            ex.printStackTrace();
        }
        return "";
    }

    /**
     * 将文本写入文件
     *
     * @param filePath 文件全路径
     * @param text     文本
     **/
    public static void WriteText2File(String filePath, String text) {
        // 创建文件
        File file = new File(filePath);
        if (!file.exists()) {
            try {
                // 创建文件父级目录
                File parentFile = file.getParentFile();
                if (!parentFile.exists()) {
                    parentFile.mkdirs();
                }
                // 创建文件
                file.createNewFile();
            }
            catch (IOException e) {
                e.printStackTrace();
            }
        }

        // 将文本写入文件
        WriteText2File(file, text);
    }

    /**
     * 将文本写入文件
     *
     * @param file 文件对象
     * @param text 文本
     **/
    public static void WriteText2File(File file, String text) {

        BufferedWriter writer = null;
        try {
            FileOutputStream writerStream = new FileOutputStream(file);
            writer = new BufferedWriter(new OutputStreamWriter(writerStream, "UTF-8"));
            writer.write(text);
            writer.flush();
        }
        catch (IOException e) {
            e.printStackTrace();
        }
        finally {
            if (writer != null) {
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


}

然后实现目录Java监控调用编译

import java.io.*;
import org.apache.commons.io.monitor.FileAlterationListenerAdaptor;
import org.apache.commons.io.monitor.FileAlterationObserver;


//监控文件
public class FileListener extends FileAlterationListenerAdaptor {
    //启动
    @Override
    public void onStart(FileAlterationObserver observer) {
        super.onStart(observer);
    }

    //新建目录
    @Override
    public void onDirectoryCreate(File directory)
    {
    }

    //目录修改
    @Override
    public void onDirectoryChange(File directory)
    {
    }

    //目录删除
    @Override
    public void onDirectoryDelete(File directory)
    {
    }

    //创建文件
    @Override
    public void onFileCreate(File file) {
        String compressedPath = file.getAbsolutePath();
        if(compressedPath.contains("AutoBuildTmp"))
        {
            return;
        }
        if (file.canRead()) {
            String confStr = compressedPath.replace(MainInit.BllJavaBasePath, "").replace("\\", "/").split("\\.")[0];
            MainMiddleware.GetObjectByConfString(confStr,null,"",compressedPath);
        }
    }

    //修改文件
    @Override
    public void onFileChange(File file) {
        String compressedPath = file.getAbsolutePath();
        if(compressedPath.contains("AutoBuildTmp"))
        {
            return;
        }
        String confStr = compressedPath.replace(MainInit.BllJavaBasePath, "").replace("\\", "/").split("\\.")[0];
        MainMiddleware.GetObjectByConfString(confStr,null,"",compressedPath);
    }

    //删除文件
    @Override
    public void onFileDelete(File file) {

    }

    //停止
    @Override
    public void onStop(FileAlterationObserver observer) {
        super.onStop(observer);
    }
}


文件侦听器

import org.apache.commons.io.monitor.FileAlterationListener;
import org.apache.commons.io.monitor.FileAlterationMonitor;
import org.apache.commons.io.monitor.FileAlterationObserver;
import org.apache.commons.io.filefilter.IOFileFilter;
import org.apache.commons.io.filefilter.FileFilterUtils;
import org.apache.commons.io.filefilter.HiddenFileFilter;

import java.io.File;

//监控文件
public class FileMonitor {

    //监视器
    private FileAlterationMonitor monitor;

    //构造函数
    public FileMonitor(long interval)
    {

        monitor = new FileAlterationMonitor(interval);
    }

    /**
     * 给文件添加监听
     *
     * @param path     文件路径
     * @param listener 文件监听器
     */
    public void monitor(String path, FileAlterationListener listener) {
        IOFileFilter directories = FileFilterUtils.and(
                FileFilterUtils.directoryFileFilter(),
                HiddenFileFilter.VISIBLE);
        IOFileFilter files       = FileFilterUtils.and(
                FileFilterUtils.fileFileFilter(),
                FileFilterUtils.suffixFileFilter(".java"));
        IOFileFilter filter = FileFilterUtils.or(directories, files);
        FileAlterationObserver observer = new FileAlterationObserver(new File(path),filter);
        monitor.addObserver(observer);
        observer.addListener(listener);
    }

    //停止
    public void stop() throws Exception {
        monitor.stop();
    }

    //启动
    public void start() throws Exception {
        monitor.start();

    }
}

主初始化实现java脚本监控

import java.nio.file.Path;
import java.nio.file.Paths;
import java.io.IOException;
import java.nio.file.*;
import java.io.*;

public class MainInit {
    //是否已经执行了初始化
    private static boolean HasInit=false;

    //网站根地址
    private static String webBasePath="";

    //业务脚本根地址
    public static String BllJavaBasePath="";

    //执行初始化
    public static void TryInit(String basePath) {
        //只初始化一次
        if (HasInit == true) {
            return;
        }
        HasInit = true;
        webBasePath = basePath;
        File fiBase=new File(basePath);
        String parentPath=fiBase.getParent();
        File fiParent=new File(parentPath);
        String codeBasePath=basePath;
        //开发环境
        if(fiParent.getName().equals("artifacts"))
        {
            //到out一级
            File fiParent1=new File(fiParent.getParent());
            //到WebUI一级
            File fiParent2=new File(fiParent1.getParent());
            codeBasePath=Paths.get(fiParent2.toString(),"web").toString()+File.separator;
        }
        //用容器的配置xml初始化容器
        LIS.Core.Context.ObjectContainer.InitIoc(basePath);
        try
        {
            BllJavaBasePath=codeBasePath;
            System.out.println("监控目录:"+codeBasePath);
            FileMonitor fileMonitor = new FileMonitor(5000);
            fileMonitor.monitor(codeBasePath, new FileListener());
            fileMonitor.start();
        }
        catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

主中间件调整

import appcode.IBaseHttpHandler;

import java.io.*;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.concurrent.ConcurrentHashMap;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Path;
import java.nio.file.Paths;

import java.util.*;


@javax.servlet.annotation.WebServlet(name = "MianMiddleware")
public class MainMiddleware extends javax.servlet.http.HttpServlet {

    /// <summary>
    /// 缓存路径和类型,允许多线程读一个线程写
    /// </summary>
    private static ConcurrentHashMap<String, Class> hsType = new ConcurrentHashMap<>();

    ///网站根地址
    public static String WebBasePath="";

    ///执行post请求
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //得到网站根路径
        if(WebBasePath=="")
        {
            WebBasePath= getServletContext().getRealPath("/");
        }
        //尝试执行初始化主逻辑
        MainInit.TryInit(WebBasePath);
        response.setContentType("text/html");
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        String url=request.getRequestURI();
        //解析得到类名
        String className = url.split("\\.")[0];
        PrintWriter writer = response.getWriter();
        //取第一部分
        if (className.charAt(0) == '/') {
            className = className.substring(1);
        }
        int index=className.indexOf("/");
        className=className.substring(index+1);
        //反射得到类型
        Object objDeal = GetObjectByConfString(className,writer,WebBasePath,"");
        //转换处理接口
        if(objDeal!=null)
        {
            //转换成接口
            appcode.IBaseHttpHandler baseDeal=(appcode.IBaseHttpHandler)objDeal;
            baseDeal.ProcessRequest(request,response);
        }
        else
        {
            Write(writer,"未找到名称为:"+className+"的处理类");
        }
    }


    /// <summary>
    /// 通过配置得当对象
    /// </summary>
    /// <param name="confStr">配置UI/login/ashx/AshDemo</param>
    /// <param name="writer">输出</param>
    /// <param name="basePath">Web根</param>
    /// <param name="isBuild">是否是编译</param>
    /// <returns></returns>
    public static Object GetObjectByConfString(String confStr,PrintWriter writer,String basePath,String javaBllClsPath) {
        try {
            //根
            if(basePath=="")
            {
                basePath=WebBasePath;
            }
            System.out.println("confStr:"+confStr);
            //不包含类型或者要强行编译就进行编译
            if (!hsType.containsKey(confStr)||javaBllClsPath!="") {
                String [] nameArr=confStr.split("/");
                String classFullName = "";
                //类代码全路径
                String classCodePath = basePath;
                for (int i = 0; i < nameArr.length; i++)
                {
                    //类代码文件全名
                    classCodePath = Paths.get(classCodePath, nameArr[i]).toString();
                    //类带命名空间的全名
                    if(classFullName!="")
                    {
                        classFullName += "." + nameArr[i];
                    }
                    else
                    {
                        classFullName = nameArr[i];
                    }
                }
                //类代码地址,后面实现用脚本编译用
                classCodePath = classCodePath + ".java";
                if(javaBllClsPath!="")
                {
                    classCodePath=javaBllClsPath;
                }
                String standardPath=Paths.get(basePath,"Conf","StandAshxProj.iml").toString();
                //编译返回
                String buildRet=appcode.AutoBuild.Build(basePath,classCodePath,classFullName,standardPath);
                System.out.println("buildRet:"+buildRet);
                //编译的jar名字
                String clsJarPath = Paths.get(basePath, "BinAshx", classFullName + ".jar").toString();
                System.out.println("加载jar包:"+clsJarPath);
                //自己生成jar包路径
                URL url = new File(clsJarPath).toURI().toURL();
                URL[] urls = new URL[]{url};
                //加载程序集,这里很重要,一定要指定父加载器,否则加载的类和父加载器的类不认为是一个类
                URLClassLoader loader = new URLClassLoader(urls, MainMiddleware.class.getClassLoader());
                //加载类
                Class c = loader.loadClass(classFullName);
                //先写死,后面执行编译和从jar包反射
                hsType.put(confStr, c);
            }
            Class c = hsType.get(confStr);
            //创建对象
            Object o = c.newInstance();
            return o;
        }
        catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    //get直接走post的逻辑
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doPost(request,response);
    }

    ///输出数据到前台
    private static void Write(PrintWriter writer,String str)
    {
        writer.println(str);
        writer.flush();
        writer.close();
    }

}

在这里插入图片描述

自动编译的临时目录结构
在这里插入图片描述

自动生成的jar包
在这里插入图片描述

在这里插入图片描述

在idea里面改业务脚本代码后用浏览器访问就能立即生效,简单高效,适用于服务型系统。整个涉及到目录文件监控、驱动javac和jar打包、反射重复加载类、文件读写等。

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

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

相关文章

Android 数据恢复的顶级软件分享

人们经常向我们询问有关 Android 数据恢复软件的信息以及它们是否有用。而且&#xff0c;我们给他们讲了两个朋友的故事——凯伦和亚历克斯。他们都丢失了 Android 手机上的一些重要数据。 丢失数据确实是一个令人心碎的时刻&#xff0c;根据丢失的文件&#xff0c;可能会让您…

Linux高级命令(扩展)三

一、date命令 1、date命令的作用 date命令的主要作用&#xff1a;用于获取计算机操作系统的系统时间 2、获取计算机的系统时间 # date 3、定制时间格式 # date "%F %T %Y %m %d %H %M %S" %F : 2020-04-03 %T : 09:45:36 %Y : 年 %m : 月 %d : 日 %H : 小时 %M…

这个超实用的门禁技巧,让办公楼安全更简单高效!

门禁监控是现代社会中不可或缺的一部分&#xff0c;用于确保安全和管理进出某个区域的人员。随着科技的不断发展&#xff0c;门禁监控已经远离了传统的机械锁和钥匙&#xff0c;变得更加智能化和高效。 客户案例 企业办公大楼 无锡某大型企业在其办公大楼内部部署了泛地缘科技…

【机器学习 | PipeLine】机器学习通用管道最佳实践!!(无论什么问题都能套上,确定不来看看?)

&#x1f935;‍♂️ 个人主页: AI_magician &#x1f4e1;主页地址&#xff1a; 作者简介&#xff1a;CSDN内容合伙人&#xff0c;全栈领域优质创作者。 &#x1f468;‍&#x1f4bb;景愿&#xff1a;旨在于能和更多的热爱计算机的伙伴一起成长&#xff01;&#xff01;&…

任正非说:只有“有为”才会“有位”,任何组织只有在流程中创造价值,才可能获得成长的机会。

你好&#xff01;这是华研荟【任正非说】系列的第28篇文章&#xff0c;让我们聆听任正非先生的真知灼见&#xff0c;学习华为的管理思想和管理理念。 一、所有一切要符合未来的作战需要&#xff0c;组织是为了作战而存在的&#xff0c;而不是作战服从组织的。 来源于任正非先生…

RK-3399pro 萤火虫firefly 官方unbuntu 固件系统安装搜狗中文输入法

RK-3399pro 萤火虫firefly 官方unbuntu 固件系统安装搜狗输入法&#xff08;适用于所有基于Ubuntu的UI桌面系统&#xff09; 一、添加中文语言支持输入法平台fcitx 1.安装fcitx sudo apt-get install fcitx 2.然后设置fcitx为开机自启动 sudo cp /usr/share/applications/fc…

Python进阶之推导式与生成器

文章目录 一、推导式1.列表推导式2.字典推导式3.集合推导式4.元组推导式&#xff08;生成器推导式&#xff09; 二、生成器1.生成器表达式2.生成器函数3.send函数 结束语 &#x1f482; 个人主页:风间琉璃&#x1f91f; 版权: 本文由【风间琉璃】原创、在CSDN首发、需要转载请联…

【数智化人物展】华院计算董事长、创始人宣晓华:通用大模型只是起点,尚需结合专业知识方能解决行业核心问题...

宣晓华 本文由华院计算董事长、创始人宣晓华投递并参与《2023中国企业数智化转型升级先锋人物》榜单/奖项评选。 大数据产业创新服务媒体 ——聚焦数据 改变商业 大模型的出现&#xff0c;正在开启着国内新一轮AI热潮。 某种程度上&#xff0c;真正在当下决定企业成败的&#…

22款奔驰S400L升级原厂 360全景影像 高清环绕的视野

您是否经历过这种场面呢&#xff1f; 停车位&#xff0c;狭窄障碍停车困难 避免盲区&#xff0c;倒车盲区危及生命安全 狭窄路段&#xff0c;无法判断是否安全通过 视角盲区&#xff0c;小孩站在视野盲区看不到 360度无缝3D全车可见&#xff0c;解决各个视角盲区&#xff…

开发一款直播弹幕游戏需要多少钱?

开发一款直播弹幕游戏需要多少钱&#xff1f;有好多朋友在咨询过弹幕游戏的开发价格后&#xff0c;都会比较吃惊&#xff0c;一款体量这么小的游戏为什么动辄就要几万块甚至十几万&#xff1f; 我来给你们说分析一下原因&#xff0c;这种游戏如果脱离开直播间&#xff0c;可以…

算法通关村第五关-黄金挑战LRU问题

大家好我是苏麟 , 今天聊聊LRU问题 , 相信学过操作系统的小伙伴并不陌生 . LRU问题 LRU的含义 LRU是Least Recently Used的缩写&#xff0c;即最近最少使用&#xff0c;是一种常用的页面置换算法&#xff0c;选择最近最久未使用的页面予以淘汰。 图解 : 如果再有其他元素就依…

ST表与RMQ(倍增表)

【概述】 RMQ : Range Maximum/minimum Query 这就是指区间最大或最小值&#xff08;区间最值&#xff09; ST表&#xff1a;Spars Table&#xff0c;一种可以解决 RMQ 的&#xff0c;基于倍增的数据结构&#xff0c;利用 ST 算法预处理打出的表&#xff0c;称为 ST 表。 …

EMC Unity存储系统如何查看SSD的使用寿命

为什么要写这个博客&#xff1f; 客户对老的EMC unity的存储系统要扩容&#xff0c;如何确定SSD磁盘是全新的还是拆机二手的&#xff1f;很多时候客户还有一个奇葩的要求&#xff0c;就是要和5年前的磁盘PN一致&#xff0c;甚至要求固件版本一致&#xff0c;最关键的还要求是全…

【LeetCode】每日一题 2023_11_4 数组中两个数的最大异或值

文章目录 刷题前唠嗑题目&#xff1a;数组中两个数的最大异或值题目描述代码与解题思路 结语 刷题前唠嗑 LeetCode? 启动&#xff01;&#xff01;&#xff01; 题目&#xff1a;数组中两个数的最大异或值 题目链接&#xff1a;421. 数组中两个数的最大异或值 题目描述 代…

分享去视频/图片水印的工具(完结篇)

简介 视频去水印是在数字时代日益重要和频繁的需求之一。水印是一种保护版权和确认身份的常见手段&#xff0c;但在某些情况下&#xff0c;水印可能会对视频内容产生负面影响&#xff0c;因此需要去除。 首先&#xff0c;视频去水印可以改善视频观看体验。有些视频平台或个人会…

非常有用的工具箱IT-Tools

什么是 IT-Tools &#xff1f; IT-Tools 汇集了 70 多种对开发人员和 IT 工作人员有用的工具。这个令人惊叹的工具的酷炫之处在于它不需要设置&#xff0c;不需要持久卷&#xff0c;您可以立即开始使用它。它包含大量工具&#xff0c;可生成密码、编辑 CSS 和 HTML 代码、文件格…

Blazor组件

Blazor组件 前言&#xff1a;博主文章仅用于学习、研究和交流目的&#xff0c;不足和错误之处在所难免&#xff0c;希望大家能够批评指出&#xff0c;博主核实后马上更改。 组件&#xff1a; Blazor 应用基于 Razor 组件&#xff0c;通常仅称为组件。 组件是 UI 的一个元素&…

自动驾驶算法(五):Informed RRT*算法讲解与代码实现(基于采样的路径规划) 与比较

目录 1 RRT*与Informed RRT* 2 Informed RRT*代码解析 3 完整代码 4 算法比较 1 RRT*与Informed RRT* 上篇博客我们介绍了RRT*算法&#xff1a;我们在找到一个路径以后我们还会反复的搜索。 Informed RRT*算法提出的动机(motivation)是能否增加渐近最优的速度呢&#xff1f;…

【腾讯云HAI域探秘】速通腾讯云HAI

速览HAI 产品简介 腾讯云高性能应用服务(Hyper Application lnventor&#xff0c;HA)&#xff0c;是一款面向 Al、科学计算的 GPU 应用服务产品&#xff0c;为开发者量身打造的澎湃算力平台。无需复杂配置&#xff0c;便可享受即开即用的GPU云服务体验。在 HA] 中&#xff0c;…

3000 台 Apache ActiveMQ 服务器易受 RCE 攻击

超过三千个暴露在互联网上的 Apache ActiveMQ 服务器容易受到最近披露的关键远程代码执行 (RCE) 漏洞的影响。 Apache ActiveMQ 是一个可扩展的开源消息代理&#xff0c;可促进客户端和服务器之间的通信&#xff0c;支持 Java 和各种跨语言客户端以及许多协议&#xff0c;包括…