存储mybatis的xml标签,动态sql 查询

news2025/1/11 21:00:25

前言:

通过表动态存储mybatis 的xml标签,通过动态sql 入参查询,方便更新查询逻辑,无需发版即可;(当前用的是 mybatis-plus ,db用的是oracle【这个无所谓】)

注意事项:这个只适用于简单的db查询拿数据,只要sql 能实现就行,局限性 于 简单的sql 拿db里面的数据!

倘若需要在 代码里面 复杂处理的逻辑,这个方法不适用!

步骤:

  1. 查询sql标签模板;
  2. 查询参数,执行sql 查询;
  3. 返回结果;

实现步骤:

1. 表结构设计: 

        存储mybatis的xml模板(oracle)

DROP TABLE "COM_DYNAMIC_QUERY";
CREATE TABLE "COM_DYNAMIC_QUERY" (
  "ID" VARCHAR2(64 BYTE) VISIBLE NOT NULL,
  "FUN_CODE" VARCHAR2(64 BYTE) VISIBLE,
  "DESCRIPTION" VARCHAR2(512 BYTE) VISIBLE,
  "SQL_TEMPLATE" VARCHAR2(4000 BYTE) VISIBLE,
  "EXEC_NUM" NUMBER(11,0) VISIBLE,
  "CREATE_BY" VARCHAR2(128 BYTE) VISIBLE,
  "CREATE_TIME" DATE VISIBLE DEFAULT SYSDATE,
  "UPDATE_BY" VARCHAR2(128 BYTE) VISIBLE,
  "UPDATE_TIME" DATE VISIBLE DEFAULT SYSDATE,
  "REMARK" VARCHAR2(256 BYTE) VISIBLE,
  "FUN_NAME" VARCHAR2(100 BYTE) VISIBLE
)
LOGGING
NOCOMPRESS
PCTFREE 10
INITRANS 1
STORAGE (
  INITIAL 65536 
  NEXT 1048576 
  MINEXTENTS 1
  MAXEXTENTS 2147483645
  BUFFER_POOL DEFAULT
)
PARALLEL 1
NOCACHE
DISABLE ROW MOVEMENT
;
COMMENT ON COLUMN "COM_DYNAMIC_QUERY"."ID" IS '主键ID';
COMMENT ON COLUMN "COM_DYNAMIC_QUERY"."FUN_CODE" IS '功能编码';
COMMENT ON COLUMN "COM_DYNAMIC_QUERY"."DESCRIPTION" IS '功能描述';
COMMENT ON COLUMN "COM_DYNAMIC_QUERY"."SQL_TEMPLATE" IS '模板';
COMMENT ON COLUMN "COM_DYNAMIC_QUERY"."EXEC_NUM" IS '执行次数';
COMMENT ON COLUMN "COM_DYNAMIC_QUERY"."CREATE_BY" IS '创建人';
COMMENT ON COLUMN "COM_DYNAMIC_QUERY"."CREATE_TIME" IS '创建时间';
COMMENT ON COLUMN "COM_DYNAMIC_QUERY"."UPDATE_BY" IS '更新人';
COMMENT ON COLUMN "COM_DYNAMIC_QUERY"."UPDATE_TIME" IS '更新时间';
COMMENT ON COLUMN "COM_DYNAMIC_QUERY"."REMARK" IS '备注';
COMMENT ON COLUMN "COM_DYNAMIC_QUERY"."FUN_NAME" IS '功能模块';
COMMENT ON TABLE "COM_DYNAMIC_QUERY" IS '可视化动态sql 查询';

 

 某条标签模板的示例:(注意事项,查询的sql 用query 前缀开来)

SELECT
		   p.machineName,
		   p.portName,
		   p.areaName,
		   ms.MACHINEPROCESSTYPE,
		   p.TRANSFERSTATE PORTSTATENAME,
		   enum.DESCRIPTION AS machineProcessTypecn,
		   subStr( p.LASTEVENTUSER  , 0, instr( p.LASTEVENTUSER  , ':' ) - 1 ) LASTEVENTUSER
		FROM
			port p
		INNER JOIN machinespec ms ON p.machinename = ms.machineName
		LEFT JOIN ENUMDEFVALUE enum ON ms.MACHINEPROCESSTYPE = enum.ENUMVALUE AND enum.ENUMNAME = 'Machine_type' 
		where 1=1
		<if test="query.detailMachineType != null and query.detailMachineType != ''">
			and ms.detailMachineType = #{query.detailMachineType}
		</if>
		order by p.machineName

2. 代码实现

  1. controller 代码:
    1.     @ApiOperation(value = "动态查询执行器")
          @PostMapping(value = "/executeDynamicQuery")
          public RestResponse<Object> executeDynamicQuery(@RequestBody HashMap<String, Object> dto){
              return RestResponse.ok(systemInformationService.executeDynamicQuery(dto));
          }

    2. service 实现
// 主方法
 public Object executeDynamicQuery(HashMap<String, Object> dto) {
        String method = (String) dto.get(TworkConstants.QUERY_METHOD);
        dto.put(TworkConstants.QUERY, dto.clone());

        // 1. 获取标签xml,根据入参的funCode
        String xmlSql = informationMapper.queryDynamicSqlByMethodCode(method);
        if (StringUtils.isEmpty(xmlSql)) {
            ExceptionUtil.error("未查询到当前动态sql模板!");
        }

        // 2. 调用mybatis的xml-sql解析方法,将<if><when><foreach>等 mybatis标签解析替换
        String parseSql = this.parseMybatisTags(xmlSql, dto);
        log.info("================"+ parseSql);
        dto.put(TworkConstants.SQL, parseSql);

        Object responseType = dto.get(TworkConstants.QUERY_TYPE);

        // 3. 根据响应类型,返回不同格式的json结构
        if (TworkConstants.QUERY_TYPE_PAGE.equals(responseType)) {
            Integer current = (Integer) dto.get(TworkConstants.PAGE_NO);
            Integer size = (Integer) dto.get(TworkConstants.LIMIT);
            Page<Map<String, Object>> pageParam = new Page<>(current, size);

            return informationMapper.executePageDynamicQuery(pageParam, dto);
        } else if (TworkConstants.QUERY_TYPE_ONE.equals(responseType)) {
            return informationMapper.executeOneDynamicQuery(dto);
        } else {
            return informationMapper.executeListDynamicQuery(dto);
        }
    }

    /**
     * 格式化标签模板的参数
     * @param xmlSql
     * @param dto
     * @return
     */
    private String parseMybatisTags(String xmlSql, HashMap<String, Object> dto) {
        String sql = "<select>" + xmlSql + "</select>";
        // 实例化解析 XML对象
        XPathParser parser = new XPathParser(sql, false, null, new XMLMapperEntityResolver());
        XNode context = parser.evalNode("/select");

        Configuration configuration = new Configuration();
        configuration.setDatabaseId("");
        TworkXMLScriptBuilder xmlScriptBuilder = new TworkXMLScriptBuilder(configuration, context);

        TworkDynamicSqlSource sqlSource = xmlScriptBuilder.parseTworkScriptNode();
        return sqlSource.getTworkParseSql(dto);
    }

                         

    /** 动态模板查询-常量值 **/
    String QUERY_METHOD = "queryMethod";

    String QUERY = "query";

    String SQL= "sql";
    String QUERY_TYPE_PAGE = "page";
    String QUERY_TYPE_LIST = "list";
    String QUERY_TYPE_ONE = "one";

    String QUERY_TYPE = "queryType";
    String PAGE_NO = "pageNo";
    String LIMIT = "limit";
// 相关的查询 xml模板
    <select id="executePageDynamicQuery" parameterType="java.util.Map" resultType="java.util.Map">
        ${query.sql}
    </select>
    <select id="executeListDynamicQuery" resultType="java.util.Map">
        ${query.sql}
    </select>
    <select id="executeOneDynamicQuery" resultType="java.util.Map">
        ${query.sql}
    </select>
    <select id="queryDynamicSqlByMethodCode" resultType="java.lang.String">
        SELECT SQL_TEMPLATE FROM "COM_DYNAMIC_QUERY" where FUN_CODE = #{code}
    </select>

    3.  2个类(TworkXMLScriptBuilder、TworkDynamicSqlSource)

        

package cn.xxx.xx.twork.controller.info;

import org.apache.ibatis.builder.SqlSourceBuilder;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.scripting.xmltags.DynamicContext;
import org.apache.ibatis.scripting.xmltags.SqlNode;
import org.apache.ibatis.session.Configuration;

public class TworkDynamicSqlSource implements SqlSource {

    private final Configuration configuration;
    private final SqlNode rootSqlNode;

    public TworkDynamicSqlSource(Configuration configuration, SqlNode rootSqlNode) {
        this.configuration = configuration;
        this.rootSqlNode = rootSqlNode;
    }

    @Override
    public BoundSql getBoundSql(Object parameterObject) {
        DynamicContext context = new DynamicContext(configuration, parameterObject);
        rootSqlNode.apply(context);
        // 执行完上面的方法,在这里可以直接获取到解析后带#{} ${}的sql
        SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
        Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
        SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
    
        // 执行完上面的方法,就会#{} ${} 给替换成jdbc的问号
        BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
        context.getBindings().forEach(boundSql::setAdditionalParameter);
        return boundSql;
    }

    public String getTworkParseSql(Object parameterObject) {
        DynamicContext context = new DynamicContext(configuration, parameterObject);
        rootSqlNode.apply(context);
        
        // 在这里可以直接获取到解析后带#{} ${}的sql
        return context.getSql();
    }

}

package cn.xxx.xx.twork.controller.info;

import org.apache.ibatis.builder.BaseBuilder;
import org.apache.ibatis.builder.BuilderException;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.parsing.XNode;
import org.apache.ibatis.scripting.defaults.RawSqlSource;
import org.apache.ibatis.scripting.xmltags.*;
import org.apache.ibatis.session.Configuration;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


public class TworkXMLScriptBuilder  extends BaseBuilder {


    private final XNode context;
    private boolean isDynamic;
    private final Class<?> parameterType;
    private final Map<String, TworkXMLScriptBuilder.NodeHandler> nodeHandlerMap = new HashMap<>();

    public TworkXMLScriptBuilder(Configuration configuration, XNode context) {
        this(configuration, context, null);
    }

    public TworkXMLScriptBuilder(Configuration configuration, XNode context, Class<?> parameterType) {
        super(configuration);
        this.context = context;
        this.parameterType = parameterType;
        initNodeHandlerMap();
    }


    private void initNodeHandlerMap() {
        nodeHandlerMap.put("trim", new TrimHandler());
        nodeHandlerMap.put("where", new WhereHandler());
        nodeHandlerMap.put("set", new SetHandler());
        nodeHandlerMap.put("foreach", new ForEachHandler());
        nodeHandlerMap.put("if", new IfHandler());
        nodeHandlerMap.put("choose", new ChooseHandler());
        nodeHandlerMap.put("when", new IfHandler());
        nodeHandlerMap.put("otherwise", new OtherwiseHandler());
        nodeHandlerMap.put("bind", new BindHandler());
    }

    public SqlSource parseScriptNode() {
        MixedSqlNode rootSqlNode = parseDynamicTags(context);
        SqlSource sqlSource;
        if (isDynamic) {
            sqlSource = new DynamicSqlSource(configuration, rootSqlNode);
            // 注释掉mybatis自带的,返回我们自己的sqlSource
//            sqlSource = new TworkDynamicSqlSource(configuration, rootSqlNode);
        } else {
            sqlSource = new RawSqlSource(configuration, rootSqlNode, parameterType);
        }
        return sqlSource;
    }

    public TworkDynamicSqlSource parseTworkScriptNode() {
        // 注释掉mybatis自带的,返回我们自己的sqlSource
        MixedSqlNode rootSqlNode = parseDynamicTags(context);

        return new TworkDynamicSqlSource(configuration, rootSqlNode);
    }

    protected MixedSqlNode parseDynamicTags(XNode node) {
        List<SqlNode> contents = new ArrayList<>();
        NodeList children = node.getNode().getChildNodes();
        for (int i = 0; i < children.getLength(); i++) {
            XNode child = node.newXNode(children.item(i));
            if (child.getNode().getNodeType() == Node.CDATA_SECTION_NODE || child.getNode().getNodeType() == Node.TEXT_NODE) {
                String data = child.getStringBody("");
                TextSqlNode textSqlNode = new TextSqlNode(data);
                if (textSqlNode.isDynamic()) {
                    contents.add(textSqlNode);
                    isDynamic = true;
                } else {
                    contents.add(new StaticTextSqlNode(data));
                }
            } else if (child.getNode().getNodeType() == Node.ELEMENT_NODE) { // issue #628
                String nodeName = child.getNode().getNodeName();
                NodeHandler handler = nodeHandlerMap.get(nodeName);
                if (handler == null) {
                    throw new BuilderException("Unknown element <" + nodeName + "> in SQL statement.");
                }
                handler.handleNode(child, contents);
                isDynamic = true;
            }
        }
        return new MixedSqlNode(contents);
    }

    private interface NodeHandler {
        void handleNode(XNode nodeToHandle, List<SqlNode> targetContents);
    }

    private class BindHandler implements NodeHandler {
        public BindHandler() {
            // Prevent Synthetic Access
        }

        @Override
        public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
            final String name = nodeToHandle.getStringAttribute("name");
            final String expression = nodeToHandle.getStringAttribute("value");
            final VarDeclSqlNode node = new VarDeclSqlNode(name, expression);
            targetContents.add(node);
        }
    }

    private class TrimHandler implements NodeHandler {
        public TrimHandler() {
            // Prevent Synthetic Access
        }

        @Override
        public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
            MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle);
            String prefix = nodeToHandle.getStringAttribute("prefix");
            String prefixOverrides = nodeToHandle.getStringAttribute("prefixOverrides");
            String suffix = nodeToHandle.getStringAttribute("suffix");
            String suffixOverrides = nodeToHandle.getStringAttribute("suffixOverrides");
            TrimSqlNode trim = new TrimSqlNode(configuration, mixedSqlNode, prefix, prefixOverrides, suffix, suffixOverrides);
            targetContents.add(trim);
        }
    }

    private class WhereHandler implements NodeHandler {
        public WhereHandler() {
            // Prevent Synthetic Access
        }

        @Override
        public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
            MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle);
            WhereSqlNode where = new WhereSqlNode(configuration, mixedSqlNode);
            targetContents.add(where);
        }
    }

    private class SetHandler implements NodeHandler {
        public SetHandler() {
            // Prevent Synthetic Access
        }

        @Override
        public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
            MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle);
            SetSqlNode set = new SetSqlNode(configuration, mixedSqlNode);
            targetContents.add(set);
        }
    }

    private class ForEachHandler implements NodeHandler {
        public ForEachHandler() {
            // Prevent Synthetic Access
        }

        @Override
        public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
            MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle);
            String collection = nodeToHandle.getStringAttribute("collection");
            String item = nodeToHandle.getStringAttribute("item");
            String index = nodeToHandle.getStringAttribute("index");
            String open = nodeToHandle.getStringAttribute("open");
            String close = nodeToHandle.getStringAttribute("close");
            String separator = nodeToHandle.getStringAttribute("separator");
            ForEachSqlNode forEachSqlNode = new ForEachSqlNode(configuration, mixedSqlNode, collection, index, item, open, close, separator);
            targetContents.add(forEachSqlNode);
        }
    }

    private class IfHandler implements NodeHandler {
        public IfHandler() {
            // Prevent Synthetic Access
        }

        @Override
        public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
            MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle);
            String test = nodeToHandle.getStringAttribute("test");
            IfSqlNode ifSqlNode = new IfSqlNode(mixedSqlNode, test);
            targetContents.add(ifSqlNode);
        }
    }

    private class OtherwiseHandler implements NodeHandler {
        public OtherwiseHandler() {
            // Prevent Synthetic Access
        }

        @Override
        public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
            MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle);
            targetContents.add(mixedSqlNode);
        }
    }

    private class ChooseHandler implements NodeHandler {
        public ChooseHandler() {
            // Prevent Synthetic Access
        }

        @Override
        public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
            List<SqlNode> whenSqlNodes = new ArrayList<>();
            List<SqlNode> otherwiseSqlNodes = new ArrayList<>();
            handleWhenOtherwiseNodes(nodeToHandle, whenSqlNodes, otherwiseSqlNodes);
            SqlNode defaultSqlNode = getDefaultSqlNode(otherwiseSqlNodes);
            ChooseSqlNode chooseSqlNode = new ChooseSqlNode(whenSqlNodes, defaultSqlNode);
            targetContents.add(chooseSqlNode);
        }

        private void handleWhenOtherwiseNodes(XNode chooseSqlNode, List<SqlNode> ifSqlNodes, List<SqlNode> defaultSqlNodes) {
            List<XNode> children = chooseSqlNode.getChildren();
            for (XNode child : children) {
                String nodeName = child.getNode().getNodeName();
                NodeHandler handler = nodeHandlerMap.get(nodeName);
                if (handler instanceof IfHandler) {
                    handler.handleNode(child, ifSqlNodes);
                } else if (handler instanceof OtherwiseHandler) {
                    handler.handleNode(child, defaultSqlNodes);
                }
            }
        }

        private SqlNode getDefaultSqlNode(List<SqlNode> defaultSqlNodes) {
            SqlNode defaultSqlNode = null;
            if (defaultSqlNodes.size() == 1) {
                defaultSqlNode = defaultSqlNodes.get(0);
            } else if (defaultSqlNodes.size() > 1) {
                throw new BuilderException("Too many default (otherwise) elements in choose statement.");
            }
            return defaultSqlNode;
        }
    }
}

3. 使用方法

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

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

相关文章

【C】带你复习有趣的函数

作者 &#xff1a;会敲代码的Steve 墓志铭&#xff1a;博学笃志&#xff0c;切问静思。 前言&#xff1a;本文旨在总结C语言函数章节的知识点、分为以下九个模块、分别是&#xff1a; 1.函数是什么 2.库函数 3.自定义函数 4.函数参数 5.函数调用 6.函数的嵌套调用和链式…

vue3计算属性和侦听与script setup区别使用

一、计算属性computed 计算属性&#xff0c;只要依赖值不变&#xff0c;那么不会重新计算计算属性将基于它们的反应依赖关系缓存&#xff0c;提高性能对于任何包含响应式数据的复杂逻辑&#xff0c;应该使用计算属性 <template><!--重复使用--><p>{{ msg.s…

Redis——好友关注、共同关注、Feed流推送

1. 好友关注 在探店图文的详情页面中&#xff0c;可以关注发布笔记的作者&#xff1a; 进到探店笔记详情页&#xff0c;会发出两个请求&#xff0c;1是判断是否已经关注&#xff0c;2是尝试关注用户的请求。 关注是User之间的关系&#xff0c;是博主与粉丝的关系&#xff0c;…

你用过猿如意吗?猿如意可以使用ChatGPT哦,这里详细介绍了猿如意的功能,为什么我建议你使用猿如意,来看看吧

文章内容介绍 你是否还在为为每次安装IDE&#xff08;集成开发工具&#xff09;要去各种网站找教程而烦恼&#xff1f;你是否还在为各种文本格式转换而头痛&#xff1f;你是否在为斗图都不过兄弟们而卑微&#xff1f;你是否在为互联网中庞大冗杂却低效的教程文档而崩溃&#x…

SpringMVC:SpringMVC响应结果(7)

响应结果1. 环境准备2. 响应页面3. 响应文本数据4. 响应JSON数据&#xff08;掌握&#xff09;4.1 响应POJO对象4.2 响应POJO集合对象1. 环境准备 项目结构 pom.xml添加Spring依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"…

Mathtype / Word OMML / Latex 公式相互转换

文章目录Part.I 快应用Part.II 详细操作Chap.I Mathtype ↔ WordChap.II Mathtype ↔ LatexChap.III Latex ↔ WordPart.I 快应用 本文介绍了除了使用 Word 和 Mathtype 之外不使用其他任何辅助软件来实现三者相互转换的方法。 项目操作方法Mathtype 转成 Word OMMLWord菜单栏→…

信息化课堂怎么控屏教学的

现在的很多学校都在建设机房进行互动教学&#xff0c;相比于传统的教学方法&#xff0c;计算机的教学方式能够直观的表达每堂课的知识点&#xff0c;过程更为新颖&#xff0c;有利于吸引学生的注意力&#xff0c;提高在学习过程中的专注力。 但是&#xff0c;在提高增加课堂中学…

redo log 和binlog的相关问题及其衍生

目录 下在两阶段提交的不同时刻&#xff0c;MySQL异常重启会出现什么现象。 那么&#xff0c; MySQL怎么知道binlog是完整的? redo log 和 binlog是怎么关联起来的? 处于prepare阶段的redo log加上完整binlog&#xff0c;重启就能恢复&#xff0c;MySQL为什么要这么设计? …

ensp环境 AC+AP组网及ACweb界面配置

1.进入交换机划分Vlan并且配置好每条链路 The device is running! <Huawei>system-view [Huawei]sysname SW1 [SW1]vlan batch 100 101 [SW1]interface GigabitEthernet 0/0/2 [SW1-GigabitEthernet0/0/2]port link-type trunk [SW1-GigabitEthernet0/0/2]port trunk…

C++:类和对象:对象的初始化和清理

1 前言&#xff1a; 构造和析构的背景 1&#xff1a;C中的面向对象来源于生活&#xff0c;每个对象都会有初始值以及对象销毁前的清理数据设置 2&#xff1a;对象的初始化和清理是两个非常重要的安全问题&#xff0c;一个对象或者变量没有初始状态&#xff0c;对其使用后果是未…

左旋咪唑大单层/青蒿素长循环/酒石酸长春瑞滨热敏/棕榈酰五肽-4柔性/Anti-HER2免疫脂质体的研究

小编今天为大家分享了左旋咪唑大单层/青蒿素长循环/酒石酸长春瑞滨热敏/棕榈酰五肽-4柔性/Anti-HER2免疫脂质体的制备研究。 青蒿素长循环脂质体的制备&#xff1a; 青蒿素(artemisinin,ART)由于溶解度差,稳定性低,限制了其应用.因此,本研究采用长循环脂质体包裹青蒿素,增强其…

RDD中groupByKey和reduceByKey区别

groupByKey和reduceByKey区别 groupByKey 每个分区不聚合&#xff0c;等最终分组完成后调用Reduce再聚合 适用于求平均数、中位数等情况 reduceByKey 每个分区并行计算先实现分区内部聚合&#xff0c;然后再将每个分区的结果做最终的聚合实现分区间聚合 等同于MR中Combin…

电商之收单系统的webhook推送重试机制

文章目录1 问题背景2 前言3 解决方案3.1 核心思路3.2 数据库设计3.3 下一次发送webhook的时间算法3.3 详细设计4 延申思考1 问题背景 作为一个收单系统&#xff0c;当获取到一笔交易的支付结果时&#xff0c;就需要发送一个webhook消息给电商系统。电商系统收到webhook消息后&a…

4. Bean的生命周期

Bean的生命周期 1.生命周期相关概念介绍 生命周期&#xff1a;从创建到消亡的完整过程bean生命周期&#xff1a;bean从创建到销毁的整体过程bean生命周期控制&#xff1a;在bean创建后到销毁前做一些事情 2. Bean销毁时机 容器关闭前触发bean的销毁 关闭容器方式&#xff…

前端基础—Ajax和XML

Ajax和XML 说到这里&#xff0c;就不得不提到另一个概念&#xff1a;Ajax&#xff08;Asynchronous JavaScript&#xff09;&#xff0c;中文可以称之为“js的异步请求”&#xff0c;国内统一称为Ajax。 Ajax的概念是每次打开新的网页时&#xff0c;不要让页面整体刷新&#…

Java学习笔记 --- MySQL-常用数据类型

一、Mysql常用数据类型 二、数值型(整数)的基本使用 使用规范&#xff1a;在能够满足需求的情况下&#xff0c; 尽量选择占用空间小的 # 演示整形的使用 # 使用tinyint来演示范围 有符号 -128 ~ 127 如果没有符号 0-255 # 1. 如果没有指定 unsigned&#xff0c;则TINYINT就是…

卡塔尔世界杯门线技术(GOAL LINE TECHNOLOGY)背后的黑科技

现代职业足球运动员踢球时足球的行进速度&#xff0c;据国际足联统计数据&#xff0c;平均速度可达 60 英里/小时。极少数爆发力超强的职业球员&#xff0c;可以将这个速度刷新到超过 100 英里/小时。比如里斯本竞技队的巴西左后卫罗尼赫伯森在 2006 年以 131.82 英里/小时的速…

HACKTHEBOX——Sunday

nmap 第一次没有进行全端口扫描&#xff0c;只发现了79和111端口&#xff0c;79端口运行着finger程序&#xff0c;111则是rpcbind。 重新扫描一次&#xff0c;这次针对全部端口进行扫描。 nmap -p- -oA nmap 10.10.10.76 然后在扫描端口详细信息 可以发现22022端口运行着ssh…

数据结构——查找最全总结(期末复习必备)

目录 查找的基本概念 线性表的查找 顺序查找 折半查找&#xff08;二分或对分查找&#xff09; 分块查找&#xff08;索引顺序查找&#xff09; 树表的查找 二叉排序树 定义&#xff1a; 二叉排序树的查找&#xff1a; 二叉排序树的插入&#xff1a; 二叉排序树的创建&…

【缺陷识别】SVM金属表面缺陷分类与测量【含GUI Matlab源码 682期】

⛄一、简介&#xff08;附lunwen、答辩PPT&#xff09; 1 题目内容 金属板广泛应用在工业生产与生产生活的各方面。由于金属板制造过程涉及到的设备、工艺等多因素的影响&#xff0c;金属板表面容易出现种类较多、形态各异的缺陷&#xff0c;这些缺陷对金属板的耐磨性、抗腐蚀…