详解MyBatis(三)

news2024/11/16 4:22:24

目录

1.#{} 和 ${}

1.1#{} 和${} 使用

Integer类型参数

 String类型参数

1.2#{} 和 ${}区别

 1.2.1#{}性能更高(预编译)

 1.2.2#{}更安全(防止SQL注入)

1.3排序功能 

 1.4like查询

2.数据库连接池

2.1连接池介绍

2.2更换连接池

 3.动态SQL

3.1 <if>标签

3.2 <trim>标签

3.3<where>标签

3.4<set>标签 

 3.5<foreach>标签

3.6<include>标签


承接上文详解MyBatis(二)

1.#{} ${}

MyBatis的参数赋值有两种方式#{}和${},接下来我们通过使用观察两者区别

1.1#{} ${} 使

Integer类型参数

@Select("select username,`password`,age,gender,phone from userinfo where id = #{id}")
UserInfo queryById(Integer id);

观察我们打印的日志:

发现我们输出的SQL语句:

select username, `password`, age, gender, phone from userinfo where id= ?

我们输出的参数并没有在后面拼接,id的值是使用 ? 进行占位,这种SQL我们称为"预编译SQL"

预编译 SQL 是一种数据库操作技术。简单来说,就是在执行 SQL 语句之前,先将包含参数占位符的 SQL 模板进行编译和准备。之后在实际运行时,只需将具体的参数值传递进去进行绑定,而无需再次对整个 SQL 语句进行重新编译。 

我们将#{}改成${}再观察打印的日志:

 可以看到, 这次的参数是直接拼接在SQL语句中了.

 String类型参数

@Select("select username,`password`,age,gender,phone from userinfo where username = #{username}")
UserInfo queryByName(String username);

 观察我们打印的日志, 结果是正常返回

 我们将#{}改成${}再观察打印的日志:

可以看到,这次的参数依然是直接拼接在SQL语句中了,但是字符串作为参数时 ,需要添加引号' '

使用${}未拼接引号导致程序报错

@Select("select username,`password`,age,gender,phone from userinfo where username = '${username}'")
UserInfo queryByName(String username);

再次运行程序:

结果正常返回

从上面两个例子可以看出:

#{} 使⽤的是预编译SQL, 通过 ?占位的⽅式,  提前对SQL进行编译, 然后把参数填充到SQL语句中,#{}会根据参数类型, 自动拼接引号' ' 

${}会直接进行字符替换, ⼀起对SQL进⾏编译. 如果参数为字符串, 需要加上引号' '  

  参数为数字类型时, 也可以加上, 查询结果不变, 但是可能会导致索引失效, 性能下降.

1.2#{} ${}区别

#{} ${} 的区别就是预编译SQL和即时SQL 的区别.

当发送⼀条SQL语句给服务器后, ⼤致流程如下:

1.  解析语法和语义, 校验SQL语句是否正确

2.  优化SQL语句, 制定执⾏计划

3.  执⾏并返回结果

⼀条 SQL如果⾛上述流程处理, 我们称之为 Immediate Statements(即时SQL)

 1.2.1#{}性能更高(预编译)

绝大多数情况下, 某⼀条 SQL 语句可能会被反复调用执行 , 或者每次执行的时候只有个别的值不同(比select where子句值不同, update set子句值不同, insert  values 值不同). 如果每次都需要经过上面的语法解析, SQL优化、SQL编译等,则效率就明显不行了.

预编译SQL ,编译⼀次之后会将编译后的SQL语句缓存起来 ,后面再次执行这条语句时,不会再次编译 (只是输入的参数不同), 省去了解析优化等过程, 以此来提高效率

 1.2.2#{}更安全(防止SQL注入)

SQL 注入是一种常见的数据库安全漏洞。

它是指攻击者通过在应用程序与数据库交互时提交恶意构造的特定字符串或数据,来改变原本 SQL 语句的逻辑和意图,从而执行非预期的操作,比如获取未经授权的数据、修改数据、执行任意系统命令等。

由于没有对用户输⼊进行充分检查 ,而SQL⼜是拼接⽽成 ,在用户输⼊参数时 ,在参数中添加⼀些 SQL关键字 ,达到改变SQL运行结果的目的 ,也可以完成恶意攻击。

 SQL注入实例:

@Select("select username,`password`,age,gender,phone from userinfo where username = '${username}'")
UserInfo queryByName(String username);

测试代码:

正常访问情况:

    @Test
    void queryByName() {
        List<UserInfo> userInfos = userInfoMapper.queryByName("Romised");
        System.out.println(userInfos.toString());
    }

结果运行正常:

SQL注入场景:先用一个单引号与前面的单引号闭合,然后再重新构建一个判断条件

    @Test
    void queryByName() {
        List<UserInfo> userInfos = userInfoMapper.queryByName("' or 1='1");
        System.out.println(userInfos.toString());
    }

结果依然被正确查询出来了, 其中参数 or被当做了SQL语句的⼀部分

将${}改成#{},再次运行程序

 可以发现,编译器将一长串数据都当做了String,所以查询结果为0,防止了SQL注入

如果发生在登录场景,则有可能判断为正确(具体看代码实现)

1.3排序功能 

从上面的例⼦中, 可以得出结论: ${} 会有SQL注入的风险, 所以我们尽量使用#{}完成查询

既然如此, 是不是 ${} 就没有存在的必要性了呢? 当然不是.

接下来我们看下${}的使用场景

Mapper实现 

@Select("select id,username,`password`,age,gender,phone from userinfo order by id ${sort}")
List<UserInfo> queryAllUserBySort(String sort);

注意:此时sort参数为String类型,但是SQL语句中,排序规则不需要加引号 ' ' ,所以此时的sort也不加引号

运行结果正常:

 将${}改成#{}再次运行:

可以发现,当使用#{sort}查询时,desc前后自动加了引号导致SQL错误

#{}会根据参数类型判断是否拼接引号,如果是String则会自动添加引号 ' ' 

除此之外, 还有表名作为参数时, 也只能使用 ${}

 1.4like查询

 使用 #{} 

@Select("select id,username,`password`,age,gender,phone from userinfo where username like #{%like%}")
List<UserInfo> queryAllUserByLike(String like);

运行结果:无法正确进行查询

 使用${}进行like查询:

@Select("select id,username,`password`,age,gender,phone from userinfo where username like '%${like}%'")
List<UserInfo> queryAllUserByLike(String like);

运行结果:查询正确

#{} 改成 ${} 可以正确查出来, 但是${}存在SQL注⼊的问题, 所以不能直接使⽤ ${}.

解决办法: 使⽤ mysql 的内置函数 concat() 来处理 ,实现代码如下:

@Select("select id,username,`password`,age,gender,phone from userinfo where username like concat('%',#{key},'%')")
List<UserInfo> queryAllUserByLike(String like);

2.数据库连接池

在上⾯Mybatis的讲解中, 我们使⽤了数据库连接池技术, 避免频繁的创建连接, 销毁连接 

2.1连接池介绍

数据库连接池负责分配、管理和释放数据库连接 ,它允许应用程序重复使用⼀个现有的数据库连接, 而不是再重新建⽴⼀个.

没有使⽤数据库连接池的情况: 每次执行SQL语句, 要先创建⼀个新的连接对象, 然后执行SQL语句, SQL 语句执行完, 再关闭连接对象释放资源. 这种重复的创建连接, 销毁连接比较消耗资源

使用数据库连接池的情况: 程序启动时, 会在数据库连接池中创建⼀定数量的Connection对象, 当客户请求数据库连接池, 从数据库连接池中获取Connection对象, 然后执行SQL, SQL语句执行完, 再把Connection归还给连接池.

数据库连接池具有以下优点:

  1. 提高性能:避免频繁创建和销毁数据库连接的开销,显著提升系统对数据库操作的响应速度
  2. 资源有效利用:合理管理连接资源,防止过多无效的连接占用系统资源。
  3. 稳定性增强:通过对连接的有效管理和监控,减少因连接问题导致的系统不稳定情况。
  4. 可配置性强:可以根据实际需求灵活调整连接池的参数,如连接数、超时时间等,以适应不同的应用场景和负载情况。

2.2更换连接池

常见的数据库连接池:

1.DBCP(DataBase Connection Pool):是 Apache 软件基金组织下的开源连接池实现

2.C3P0:一个被广泛使用的连接池,配置相对灵活。

3.Hikari:以高性能著称。

4.Druid:功能较为强大,提供了丰富的监控和统计功能

Hikari : SpringBoot默认使⽤的数据库连接池:

 

如果我们想把默认的数据库连接池切换为Druid据库连接池, 只需要引⼊相关依赖即可

引入Druid:

 <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.17</version> 
 </dependency>

•  Druid连接池是阿⾥巴巴开源的数据库连接池项⽬

•  功能强大,性能优秀,是Java语⾔最好的数据库连接池之⼀

 3.动态SQL

动态 SQL Mybatis的强⼤特性之⼀ ,能够完成不同条件下不同的 sql 拼接。 

3.1 <if>标签

在注册用户的时候 ,可能会有这样⼀个问题 ,如下图所示:

 

注册分为两种字段:必填字段和非必填字段 ,那如果在添加用户的时候有不确定的字段传入

这时就需要使用动态标签来判断了,如添加的时候性别gender 为⾮必填字段具体实现如下:

接口定义:

Integer insertUserByCondition(UserInfo userInfo);

Mapper.xml实现:

 <insert id="insertUserByCondition">
     INSERT INTO userinfo (
     username,
     `password`, 
     age,
     <if test="gender != null">
        gender,
     </if>
     phone)
     VALUES (
     #{username},
     #{age},
     <if test="gender != null">
        #{gender},
     </if>
     #{phone})
 </insert>

或者使用注解方式(不推荐)

把上面的SQL(包括标签),使用<script></script>标签括起来就可以

 @Insert("<script>" +
         "INSERT INTO userinfo (username,`password`,age," +
         "<if test='gender!=null'>gender,</if>" +
         "phone)" +
         "VALUES(#{username},#{age}," +
         "<if test='gender!=null'>#{gender},</if>" +
         "#{phone})"+
         "</script>")
 Integer insertUserByCondition(UserInfo userInfo);

注意 test 中的gender ,是传⼊对象中的属性 ,不是数据库字段

Q: 可不可以不进⾏判断, 直接把字段设置为null?

A: 不可以, 这种情况下, 如果gender字段有默认值, 就会设置为默认值

 上述案例通过<if>标签判定个别传入数据是否为空,如果不为空的语句是:

insert into userinfo (username,`password`,age,gender,`phone`) 
values (#{username},#{password},#{age},#{gender},#{phone});

 如果gender和phone传入对象为空,则语句变成:

insert into userinfo (username,`password`,age) 
values (#{username},#{password},#{age});

注意:编写代码时要注意逗号等位置,避免某个元素为空时逗号多余

3.2 <trim>标签

在 MyBatis 中,<trim>标签主要用于对 SQL 语句进行灵活的拼接和处理。

标签中有如下属性:

•  prefix:表示整个语句块 ,以prefix的值作为前缀   

•  suffix:表示整个语句块 ,以suffix的值作为后缀   

•  prefixOverrides:表示整个语句块要去除掉的前缀

•  suffixOverrides:表示整个语句块要去除掉的后缀 

 调整 Mapper.xml 的插⼊语句为:

 <insert id="insertUserByCondition">
     INSERT INTO userinfo
     <trim prefix="(" suffix=")" suffixOverrides=",">
         <if test="username !=null">
            username,
         </if>
         <if test="password !=null">
            `password`,
         </if>
         <if test="age != null">
            age,
         </if>
         <if test="gender != null">
            gender,
         </if>
         <if test="phone != null">
            phone,
         </if>
     </trim>
     VALUES
     <trim prefix="(" suffix=")" suffixOverrides=",">
         <if test="username !=null">
            #{username},
         </if>
         <if test="password !=null">
            #{password},
         </if>
         <if test="age != null">
            #{age},
         </if>
         <if test="gender != null">
            #{gender},
         </if>
         <if test="phone != null">
            #{phone}
         </if>
     </trim>
 </insert>

或者使用注解方式(不推荐)

 @Insert("<script>" +
         "INSERT INTO userinfo " +
         "<trim prefix='(' suffix=')' suffixOverrides=','>" +
         "<if test='username!=null'>username,</if>" +
         "<if test='password!=null'>password,</if>" +
         "<if test='age!=null'>age,</if>" +
         "<if test='gender!=null'>gender,</if>" +
         "<if test='phone!=null'>phone,</if>" +
         "</trim>" +
         "VALUES " +
         "<trim prefix='(' suffix=')' suffixOverrides=','>" +
         "<if test='username!=null'>#{username},</if>" +
         "<if test='password!=null'>#{password},</if>" +
         "<if test='age!=null'>#{age},</if>" +
         "<if test='gender!=null'>#{gender},</if>" +
         "<if test='phone!=null'>#{phone}</if>" +
         "</trim>"+
         "</script>")
 Integer insertUserByCondition(UserInfo userInfo);

在以上sql动态解析时,会做如下处理:
基于prefix配置,开始部分加上左括号(  基于suffix配置,结束部分加上有括号) 基于suffixOverrides配置,去掉最后一个逗号,

3.3<where>标签

看下面这个场景, 系统会根据我们的筛选条件, 动态组装where 条件

需求: 传入的用户对象 ,根据属性做where条件查询

原有SQL:

 SELECT
        *
 FROM
        userinfo
 WHERE
        age = 18
        AND gender = 1
        AND delete_flag =0;

接口定义:

List<UserInfo> queryByCondition();

Mapper.xml实现:

 <select id="queryByCondition" resultType="com.example.demo.model.UserInfo">
     select id, username, age, gender, phone, delete_flag, create_time, update_ti
     from userinfo
     <where>
         <if test="age != null">
            and age = #{age}
         </if>
         <if test="gender != null">
            and gender = #{gender}
         </if>
         <if test="deleteFlag != null">
            and delete_flag = #{deleteFlag}
         </if>
     </where>
 </select>

 注解方式实现:

 @Select("<script>select id, username, age, gender, phone, delete_flag, create_ti
         "   from userinfo" +
         "   <where>" +
         "        <if test='age != null'> and age = #{age} </if>" +
         "        <if test='gender != null'> and gender = #{gender} </if>" +
         "        <if test='deleteFlag != null'> and delete_flag = #{deleteFlag}
         "   </where>" +
         "</script>")
 List<UserInfo> queryByCondition(UserInfo userInfo);

<where>标签只会在⼦元素有内容的情况下才插入where⼦句 ,而且会⾃动去除⼦句的开头的ANDOR

3.4<set>标签 

需求: 根据传入的用户对象属性来更新⽤户数据 ,可以使用标签来指定动态内容. 

接⼝定义: 根据传入的用户id 属性 ,修改其他不为 null 的属性

Integer updateUserByCondition(UserInfo userInfo);

Mapper.xml实现:

 <update id="updateUserByCondition">
     update userinfo
     <set>
         <if test="username != null">
            username = #{username},
         </if>
         <if test="age != null">
            age = #{age},
         </if>
         <if test="deleteFlag != null">
            delete_flag = #{deleteFag},
         </if>
     </set>
     where id = #{id}
 </update>

注解方式实现:

 @Update("<script>" +
         "update userinfo " +
         "<set>" +
         "<if test='username!=null'>username=#{username},</if>" +
         "<if test='age!=null'>age=#{age},</if>" +
         "<if test='deleteFlag!=null'>delete_flag=#{deleteFlag},</if>" +
         "</set>" +
         "where id=#{id}" +
         "</script>")
 Integer updateUserByCondition(UserInfo userInfo);

<set>标签主要用于动态生成 UPDATE 语句中的 SET 子句。它可以根据条件动态地设置需要更新的字段,并且能够自动处理字段值为空或不合法的情况,避免错误地更新到数据库中。

 3.5<foreach>标签

对集合进行遍历时可以使⽤该标签。标签有如下属性:

•  collection :绑定⽅法参数中的集合 ,如 List Set Map或数组对象

  item :遍历时的每⼀个对象

  open :语句块开头的字符串

  close:语句块结束的字符串

•  separator:每次遍历之间间隔的字符串 

需求: 根据多个userid, 删除用户数据

接口方法:

void deleteByIds(List<Integer> ids);

ArticleMapper.xml 中新增删除 sql

 <delete id="deleteByIds">
     delete from userinfo
     where id in
     <foreach collection="ids" item="id" separator="," open="(" close=")">
        #{id}
     </foreach>
 </delete>

或者使用注解方式:

 @Delete("<script>" +
            "delete from userinfo where id in" +
             "<foreach collection='ids' item='id' separator=',' open='(' close=')
            "#{id}" +
            "</foreach>" +
         "</script>")
 Integer deleteUser(Integer id);

3.6<include>标签

问题分析:xml映射文件中配置的SQL ,可能存在很多重复的片段 ,此时就会存在很多冗余的代码

我们可以对重复的代码片段进行抽取,将其通过<sql>标签封装到一个SQL片段,然后再通过<include>标签进行引用

 <sql>: 定义可重用的SQL片段

<include>:通过属性refid,制定包含的SQL片段

 通过<include>标签在原来抽取的地方进行引用,操作如下:

 <select id="queryAllUser" resultMap="BaseMap">
     select
     <include refid="allColumn"></include>
     from userinfo
 </select>
 <select id="queryById" resultType="com.example.demo.model.UserInfo">
     select
     <include refid="allColumn"></include>
     from userinfo where id= #{id}
 </select>

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

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

相关文章

http接口上传文件响应413:413 Request Entity Too Large

目录 一、场景简介二、异常展示三、原因四、解决 一、场景简介 1、服务端有经过nginx代理 2、上传文件超过5M时&#xff0c;响应码为413 3、上传文件小于5M时&#xff0c;上传正常 二、异常展示 三、原因 nginx限制了上传数据的大小 四、解决 扩大nginx上传数据的大小 步…

44-5 waf绕过 - SQL注入绕WAF方法

环境准备: 43-5 waf绕过 - 安全狗简介及安装-CSDN博客然后安装sqlilabs靶场:构建完善的安全渗透测试环境:推荐工具、资源和下载链接_渗透测试靶机下载-CSDN博客 一、双写绕过 打开sql靶场的第一关:http://127.0.0.1/sqli-labs-master/Less-1/?id=1 验证一下waf是否开启防…

Win10下CodeBlock实现socket TCP server/client

文章目录 1 安装codeblock2 适配libws2_32.a库3 TCP socket工作原理4 代码实现服务端客户端5 运行效果1 安装codeblock 官方免费下载 值得一提的是,安装时,指定安装路径,其他默认安装即可 2 适配libws2_32.a库 默认安装,只有3个库,如果编译socket,需要专门的库libws2…

阿奇科技 简单java-swing计算器源码(可用于课设等)

此系统用的技术有java swing&#xff01; 实现的功能&#xff1a; 加减乘除&#xff08;可以进行小数运算&#xff09; 清空数据 最小化 小巧方便&#xff0c;功能齐全&#xff01; 页面截图: 源码地址&#xff1a;点击这里下载源码 获取全套代码&#xff0c;或咨询更多代码…

自动装车系统车辆定位-激光雷达解决方案

在自动装车系统中&#xff0c;激光雷达为车辆定位提供了一种高效且精确的解决方案。以下是关于这一解决方案的详细分析&#xff1a; 一、解决方案概述 激光雷达解决方案在自动装车系统中&#xff0c;通过发射激光束并接收目标反射回来的信号&#xff0c;来探测车辆的位置、状…

K8s(Kubernetes)常用命令

大家好&#xff0c;当谈及容器编排工具时&#xff0c;Kubernetes&#xff08;常简称为K8s&#xff09;无疑是当今最受欢迎和广泛使用的解决方案之一。作为一个开源的容器编排平台&#xff0c;Kubernetes 提供了丰富的功能&#xff0c;可以帮助开发人员和运维团队管理、部署和扩…

今日份动态规划学习(二维01背包+01背包变形)

目录 P1877 [HAOI2012] 音量调节 P1877 [HAOI2012] 音量调节 题解&#xff1a;一个入门级别的01背包问题&#xff0c;首先就是为什么能看出是01背包&#xff0c;因为只有两种状态&#xff0c;要不增大音量&#xff0c;要不减小音量&#xff0c;和01背包的选与不选非常近似。但…

计算机网络 —— 数据链路层(以太网)

计算机网络 —— 数据链路层&#xff08;以太网&#xff09; 什么是以太网以太网传输介质和拓扑结构的发展传输介质的发展&#xff1a;拓扑结构的发展&#xff1a; 10BASE-T 以太网适配器和MAC地址适配器&#xff08;Adapter&#xff09;MAC地址适配器与MAC地址的关系 MAC帧以太…

OpenCV中的圆形标靶检测——斑点检测算法(二)

前面的章节中我们已经大致介绍了算法流程,也对一些算法中用到的相关概念做了简要介绍,同时给出了算法调用的API,现在我们开始算法检测接口实现源码的分析。 1. 斑点的分组与加权 这里我们选择后者,先了解算法的处理流程,再分析各个模块的实现。算法流程图如下图所示,上一…

重生之 SpringBoot3 入门保姆级学习(10、日志基础与使用)

重生之 SpringBoot3 入门保姆级学习&#xff08;10、日志基础使用&#xff09; 3.1 日志基础3.2 使用日志3.2.1 基础使用3.2.2 调整日志级别3.2.3 带参数的日志 3.1 日志基础 SpringBoot 默认使用 SLF4j&#xff08;Simple Logging Facade for Java&#xff09;和 Logback 实现…

结构体+结构体内存对齐+结构体实现位段

结构体内存对齐实现位段 一.结构体1.结构体的声明2.结构体变量成员访问操作符3.结构体传参4.匿名结构体5.结构的自引用 二.结构体内存对齐1.对齐规则2.为什么存在内存对齐&#xff1f;3.修改默认对齐数 三.结构体实现位段1.什么是位段2.位段的内存分配3.位段的跨平台问题4.位段…

C++标准模板(STL)- 迭代器库-迭代器适配器 - 逆序遍历的迭代器适配器

迭代器库-迭代器适配器 迭代器库提供了五种迭代器的定义&#xff0c;同时还提供了迭代器特征、适配器及相关的工具函数。 迭代器分类 迭代器共有五 (C17 前)六 (C17 起)种&#xff1a;遗留输入迭代器 (LegacyInputIterator) 、遗留输出迭代器 (LegacyOutputIterator) 、遗留向…

2024年城市建设与环境管理国际会议(ICUCEM 2024)

2024 International Conference on Urban Construction and Environmental Management 【1】大会信息 大会地点&#xff1a;中国成都 投稿邮箱&#xff1a;icucemsub-paper.com 【2】会议简介 2024年城市建设与环境管理国际会议是一个专注于探讨城市建设与环境管理前沿议题…

#02 安装指南:如何配置Stable Diffusion环境

文章目录 前言前置条件第1步&#xff1a;安装Python和PIP第2步&#xff1a;创建虚拟环境第3步&#xff1a;安装PyTorch和CUDA第4步&#xff1a;安装Stable Diffusion相关库第5步&#xff1a;测试环境结论 前言 在之前的文章中&#xff0c;我们介绍了Stable Diffusion基础入门和…

【ArcGIS微课1000例】0114:基于DEM地形数据整体抬升或下降高程

相关阅读:【GlobalMapper精品教程】083:基于DEM整体抬升或下降地形高程的两种方式 文章目录 一、任务分析二、栅格计算器简介三、地形整体修改四、注意事项一、任务分析 打开软件,加载配套实验数据中的0112.rar中的dem数据,如下所示,dem的高程范围为256.75~342.37米,现在…

QT之动态加载树节点(QTreeWidget)

之前写过一篇动态加载ComboBox&#xff0c;可参见下面这篇文章 QT之动态加载下拉框&#xff08;QComboBox&#xff09; 同理QTreeWidget也可以实现动态加载&#xff0c;在一些异步加载数据&#xff0c;并且数据加载比较耗时&#xff0c;非常实用。 效果 原理分析 要实现此类效…

618精选网络安全书单:打造数字世界的钢铁长城!

文章目录 《内网渗透实战攻略》《Kali Linux高级渗透测试&#xff08;原书第4版&#xff09;》《CTF那些事儿》《权限提升技术&#xff1a;攻防实战与技巧》《数字政府网络安全合规性建设指南&#xff1a;密码应用与数据安全》《红蓝攻防&#xff1a;构建实战化网络安全防御体系…

ECharts 图形化看板 模板(简单实用)

目录 一、官网 二、模板 ①定义请求​编辑 ② 将请求统一管理&#xff0c;别的页面引用多个请求时更便于导入。​编辑 ③最终模板 三、执行效果 四、后端代码 4.1 controller 4.2 xml 4.3 测试接口 一、官网 获取 ECharts - 入门篇 - 使用手册 - Apache ECharts 二、…

医疗器械网络安全风险管理的基本步骤

医疗器械网络安全风险管理是一个复杂的过程&#xff0c;涉及到多个环节和步骤。以下是一些基本的步骤和关键点&#xff1a; 风险识别&#xff1a;首先需要对医疗器械的软件、网络连接和通信协议等进行漏洞分析&#xff0c;识别潜在的安全漏洞和弱点。这可能涉及对设备的渗透测…

佛教祭拜小程序-寺庙小程序-纪念馆小程序

大家好&#xff0c;我是程序员小孟。 现在有很多的产品或者工具都开始信息话了&#xff0c;寺庙或者佛教也需要小程序吗&#xff1f; 当然了&#xff01; 前面我们还开发了很多寺庙相关的小程序&#xff0c;都有相关的介绍&#xff1a; 1,优质的寺庙小程序-H5寺庙网页 今天…