Mybatis(2)

sql注入攻击

SQL注入攻击是一种常见的网络安全威胁,攻击者通过在输入字段中插入恶意SQL代码,绕过应用程序的安全机制,直接操纵数据库。

SQL注入的原理

SQL注入利用应用程序未对用户输入进行充分过滤或转义的漏洞。当用户输入被直接拼接到SQL查询中时,攻击者可以构造特殊输入,改变查询逻辑,获取未授权的数据或执行恶意操作。

-- 示例:通过输入' OR '1'='1绕过登录验证
SELECT * FROM users WHERE username = 'admin' AND password = '' OR '1'='1';

SQL注入攻击是一种常见的网络安全威胁,攻击者通过在输入字段中插入恶意SQL代码,绕过应用程序的安全机制,直接操纵数据库。以下是关于SQL注入攻击的详细说明:

常见的SQL注入类型

基于错误的注入
攻击者通过故意引发数据库错误,从错误信息中获取数据库结构或敏感数据。

联合查询注入
利用UNION操作符将恶意查询结果合并到正常查询结果中,获取其他表的数据。

-- 示例:获取其他表数据
SELECT id, name FROM products WHERE id = 1 UNION SELECT username, password FROM users;

盲注
当应用程序不返回错误信息时,攻击者通过布尔条件或时间延迟判断查询结果。

-- 布尔盲注示例
SELECT * FROM users WHERE username = 'admin' AND SUBSTRING(password, 1, 1) = 'a';

防御SQL注入的方法

参数化查询(预编译语句)
使用参数化查询确保用户输入始终被视为数据而非代码。

# Python示例(使用SQLite)
import sqlite3
conn = sqlite3.connect('database.db')
cursor = conn.cursor()
cursor.execute("SELECT * FROM users WHERE username = ? AND password = ?", (username, password))

输入验证与过滤
对用户输入进行严格验证,仅允许符合预期的字符或格式。

最小权限原则
数据库账户应仅具有必要的最小权限,避免使用高权限账户连接数据库。

使用ORM框架
ORM(如Django ORM、SQLAlchemy)自动处理参数化查询,减少手动拼接SQL的需求。

# Django ORM示例
from django.db import models
User.objects.filter(username=username, password=password)

静态SQL与动态SQL的区别

静态SQL和动态SQL是数据库编程中两种不同的SQL语句处理方式,它们在编写方式、执行效率和适用场景上有显著差异。

静态SQL

静态SQL是指在程序编译时就已确定的SQL语句,通常直接嵌入在源代码中。这些语句的结构和参数在编译时已知,数据库管理系统(DBMS)可以预先优化。

特点

  • 语句在编译时固定,无法在运行时改变。
  • 性能较高,因为DBMS可以预编译和优化。
  • 通常用于参数化查询,参数通过占位符(如?@param)传递。

示例代码(Java中使用JDBC)

String sql = "SELECT * FROM employees WHERE department_id = ?";
PreparedStatement stmt = connection.prepareStatement(sql);
stmt.setInt(1, 10); // 设置参数
ResultSet rs = stmt.executeQuery();

动态SQL

动态SQL是指在程序运行时动态构建的SQL语句,通常根据用户输入或其他运行时条件生成。语句的结构或内容可能在运行时变化。

特点

  • 语句在运行时动态生成,灵活性高。
  • 性能较低,因为DBMS无法预编译。
  • 容易引发SQL注入风险,需谨慎处理输入。

示例代码(Java中使用JDBC)

String departmentId = getUserInput(); // 用户输入
String sql = "SELECT * FROM employees WHERE department_id = " + departmentId;
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery(sql);

安全性与性能对比

静态SQL

  • 安全性高:参数化查询避免SQL注入。
  • 性能优:预编译减少运行时开销。

动态SQL

  • 安全性低:直接拼接输入可能导致注入。
  • 性能差:每次执行需重新解析和优化。

例子

数据库设计:

实体类代码:

package com.qcby.entity;public class student {private Integer id;private  String name;private  String sex;private  String phone;private  String password;private  Integer age;private Integer pageSize;private  Integer pageStart;public student() {}public student(String name, String sex, String phone, Integer age) {this.name = name;this.sex = sex;this.phone = phone;this.age = age;}public Integer getPageSize() {return pageSize;}public void setPageSize(Integer pageSize) {this.pageSize = pageSize;}public Integer getPageStart() {return pageStart;}public void setPageStart(Integer pageStart) {this.pageStart = pageStart;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public String getPhone() {return phone;}public void setPhone(String phone) {this.phone = phone;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic String toString() {return "student{" +"id=" + id +", name='" + name + '\'' +", sex='" + sex + '\'' +", phone='" + phone + '\'' +", password='" + password + '\'' +", age=" + age +'}';}
}

dao层代码

package com.qcby.dao;import com.qcby.entity.student;
import org.apache.ibatis.annotations.Param;import java.util.List;public interface  StudentDao {public  abstract List<student> findAll();student findById(Integer id);Integer delete(Integer id);List<student> findByName(String name);List<student> findBystudent(student student);Integer insert(student student);Integer insertGetId(student student);List<student> findAllStudent(Integer pageSize,Integer pageStart);List<student> findAllStudentByAge (student student);List<student> findUserByStudentName(String name);List<student> findUser(student student);int update(student student);List<student> selectUserByChoose(student student);List<student> selectUserByUsernameAndSex(student student);int trimUpdate(student student);int deleteMoreByArray(@Param("ids") Integer[] ids);int insertMoreByList(@Param("students") List<student> students);
}

mapper.xml代码

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qcby.dao.StudentDao"><select id="findAll" resultType="com.qcby.entity.student">SELECT * FROM student</select><select id="findById" resultType="com.qcby.entity.student" parameterType="java.lang.Integer">SELECT * from student WHERE id=#{id}</select><delete id="delete" parameterType="java.lang.Integer">DELETE from student WHERE id=#{id}</delete><select id="findByName" resultType="com.qcby.entity.student" parameterType="java.lang.String">SELECT  * from student where name=#{name}</select><select id="findBystudent" resultType="com.qcby.entity.student" parameterType="com.qcby.entity.student">SELECT  * from student where name=#{name} and password=#{password}</select><insert id="insert" parameterType="com.qcby.entity.student">INSERT  INTO student(name,sex,phone,password,age) VALUES (#{name},#{sex},#{phone},#{password},#{age})</insert><insert id="insertGetId" parameterType="com.qcby.entity.student"><selectKey keyProperty="id" resultType="int" order="AFTER">select LAST_INSERT_ID();</selectKey>INSERT INTO student(name,sex,phone,password,age) VALUES (#{name},#{sex},#{phone},#{password},#{age})</insert><select id="findAllStudent" parameterType="java.lang.Integer" resultType="com.qcby.entity.student">SELECT * from student limit #{param1} offset #{param2}</select><select id="findAllStudentByAge" resultType="com.qcby.entity.student" parameterType="com.qcby.entity.student">select * from student WHERE name=#{name} limit #{pageSize} offset #{pageStart}</select><select id="findUserByStudentName" parameterType="java.lang.String" resultType="com.qcby.entity.student">select * from student where name like #{value}</select><!-- where if --><select id="findUser" resultType="com.qcby.entity.student" parameterType="com.qcby.entity.student">select * from student<where><if test="name!=null and name!=''">AND name=#{name}</if><if test="sex!=null and sex!=''">AND sex=#{sex}</if><if test="phone!=null and phone!=''">AND phone=#{phone}</if><if test="password!=null and password!=''">AND password=#{password}</if><if test="age!=null and age!=''">AND age=#{age}</if></where></select><update id="update" parameterType="com.qcby.entity.student">UPDATE student<set><if test="name!=null and name!=''">name=#{name},</if><if test="sex!=null and sex!=''">sex=#{sex},</if><if test="phone!=null and phone!=''">phone=#{phone},</if><if test="password!=null and password!=''">password=#{password},</if><if test="age!=null and age!=''">age=#{age}</if></set>WHERE id = #{id}</update>
<!--if elseif else--><select id="selectUserByChoose" resultType="com.qcby.entity.student"            parameterType="com.qcby.entity.student">select * from student<where><choose><when test="name!=null and name!=''">AND name=#{name}</when><when test="sex!=null and sex!=''">AND sex=#{sex}</when><otherwise>and id=#{id}</otherwise></choose></where></select><select id="selectUserByUsernameAndSex" resultType="com.qcby.entity.student" parameterType="com.qcby.entity.student">SELECT * from student<trim prefix="where" prefixOverrides="and | or"><if test="name!=null and name!=''">AND name=#{name}</if><if test="sex!=null and sex!=''">AND sex=#{sex}</if><if test="phone!=null and phone!=''">AND phone=#{phone}</if><if test="password!=null and password!=''">AND password=#{password}</if><if test="age!=null and age!=''">AND age=#{age}</if></trim></select>
<update id="trimUpdate" parameterType="com.qcby.entity.student">update student<trim prefix="set" suffixOverrides=","><if test="name!=null and name!=''">name=#{name},</if><if test="sex!=null and sex!=''">sex=#{sex},</if><if test="phone!=null and phone!=''">phone=#{phone},</if><if test="password!=null and password!=''">password=#{password},</if><if test="age!=null and age!=''">age=#{age},</if></trim>where id = #{id}
</update><!--delete from user where id in (1,2,3,4,5); --><delete id="deleteMoreByArray">DELETE FROM student WHERE id IN<foreach collection="ids" item="id" separator="," open="(" close=")">#{id}</foreach></delete><!-- collection:当前要循环的数组或者集合   --><!--  item: 我们指定要循环的数组的每一个元素  --><!-- separator:每一个元素应该用什么来做分割   --><!-- open:当前循环是以什么开始   --><!-- close:当前循环是以什么结束   --><!--insert into 表名 (字段) values (值),(值)--><insert id="insertMoreByList" >insert into student(name,age,sex,phone) values<foreach collection="students" item="student" separator=",">(#{student.name},#{student.age},#{student.sex},#{student.phone})</foreach></insert>
</mapper>

1. 基本结构与命名空间

<mapper namespace="com.qcby.dao.StudentDao">

这个标签确定了命名空间为com.qcby.dao.StudentDao,这意味着在 Java 代码里可以通过该命名空间来调用这些 SQL 映射语句。

2. 基础 CRUD 操作

  • 查询全部学生
    <select id="findAll" resultType="com.qcby.entity.student">SELECT * FROM student
    </select>
    
    此语句会返回student表中的所有记录。
  • 按 ID 查询学生
    <select id="findById" resultType="com.qcby.entity.student" parameterType="java.lang.Integer">SELECT * from student WHERE id=#{id}
    </select>
    
    它依据传入的 ID 参数来查找对应的学生。
  • 插入学生
    <insert id="insert" parameterType="com.qcby.entity.student">INSERT  INTO student(name,sex,phone,password,age) VALUES (#{name},#{sex},#{phone},#{password},#{age})
    </insert>
    
    该语句用于向表中插入新的学生记录。
  • 更新学生信息
    <update id="update" parameterType="com.qcby.entity.student">UPDATE student<set><if test="name!=null and name!=''">name=#{name},</if><!-- 其他字段的更新条件类似 --></set>WHERE id = #{id}
    </update>
    
    借助<set>标签和<if>条件判断,能够动态地更新学生信息。
  • 删除学生
    <delete id="delete" parameterType="java.lang.Integer">DELETE from student WHERE id=#{id}
    </delete>
    
    此语句会删除指定 ID 的学生记录。

3. 动态 SQL 元素

  • <where>标签
    <select id="findUser" resultType="com.qcby.entity.student" parameterType="com.qcby.entity.student">select * from student<where><if test="name!=null and name!=''">AND name=#{name}</if><!-- 其他条件判断 --></where>
    </select>
    
    当有条件满足时,<where>标签会自动添加WHERE关键字,并且能智能地去除多余的ANDOR
  • <choose><when><otherwise>标签
    <select id="selectUserByChoose" resultType="com.qcby.entity.student" parameterType="com.qcby.entity.student">select * from student<where><choose><when test="name!=null and name!=''">AND name=#{name}</when><otherwise>and id=#{id}</otherwise></choose></where>
    </select>
    
    这组标签类似于 Java 中的switch-case语句,会按顺序进行条件判断,一旦有条件满足就会停止后续判断。
  • <trim>标签
    <update id="trimUpdate" parameterType="com.qcby.entity.student">update student<trim prefix="set" suffixOverrides=","><!-- 更新字段 --></trim>where id = #{id}
    </update>
    
    <trim>标签可以自定义前缀和后缀,suffixOverrides属性能够移除多余的逗号。

4. 批量操作

  • 批量删除
    <delete id="deleteMoreByArray">DELETE FROM student WHERE id IN<foreach collection="ids" item="id" separator="," open="(" close=")">#{id}</foreach>
    </delete>
    
    <foreach>标签会对集合进行遍历,可用于生成IN条件。
  • 批量插入
    <insert id="insertMoreByList" >insert into student(name,age,sex,phone) values<foreach collection="students" item="student" separator=",">(#{student.name},#{student.age},#{student.sex},#{student.phone})</foreach>
    </insert>
    
    利用<foreach>标签能够批量插入多条学生记录。

5. 分页查询

<select id="findAllStudent" parameterType="java.lang.Integer" resultType="com.qcby.entity.student">SELECT * from student limit #{param1} offset #{param2}
</select>

此查询通过limitoffset实现分页功能,param1代表每页的记录数,param2代表偏移量。

6. 自动获取主键

<insert id="insertGetId" parameterType="com.qcby.entity.student"><selectKey keyProperty="id" resultType="int" order="AFTER">select LAST_INSERT_ID();</selectKey>INSERT INTO student(name,sex,phone,password,age) VALUES (#{name},#{sex},#{phone},#{password},#{age})
</insert>

<selectKey>标签的作用是在插入数据后获取自动生成的主键,并将其赋值给实体类的id属性。

Test代码

import com.qcby.dao.StudentDao;
import com.qcby.dao.UserDao;
import com.qcby.entity.User;
import com.qcby.entity.student;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
public class StudentTest {private InputStream in = null;private SqlSession session = null;private StudentDao mapper = null;@Before  //前置通知, 在方法执行之前执行public void init() throws IOException {//加载主配置文件,目的是为了构建SqlSessionFactory对象in = Resources.getResourceAsStream("SqlMapConfig.xml");//创建SqlSessionFactory对象SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);//通过SqlSessionFactory工厂对象创建SqlSesssion对象session = factory.openSession();//通过Session创建UserDao接口代理对象mapper = session.getMapper(StudentDao.class);}@After  //@After: 后置通知, 在方法执行之后执行 。public void destory() throws IOException {//释放资源session.close();in.close();}@Testpublic void SELETALL(){List<student>  students = mapper.findAll();for (student student: students) {System.out.println(student.toString());}}@Testpublic  void findById(){student student=mapper.findById(1);System.out.println(student.toString());}@Testpublic void  delete(){mapper.delete(1);List<student>  students = mapper.findAll();for (student student: students) {System.out.println(student.toString());}session.commit();}@Testpublic  void findByName(){List<student> students=mapper.findByName("杨");for(student students1:students){System.out.println(students1.toString());}}@Testpublic void findBystudent(){student student=new student();student.setName("yu");student.setPassword("123456");List<student> students=mapper.findBystudent(student);for (student student1: students) {System.out.println(student1.toString());}}
@Testpublic  void insert(){student student=new student();student.setName("11");student.setPassword("123");student.setAge(11);student.setPhone("12345");student.setSex("男");mapper.insert(student);List<student>  students = mapper.findAll();for (student student1: students) {System.out.println(student1.toString());}session.commit();}@Testpublic  void insertGetId(){student student=new student();student.setName("11");student.setPassword("123");student.setAge(11);student.setPhone("12345");student.setSex("男");mapper.insertGetId(student);List<student>  students = mapper.findAll();for (student student1: students) {System.out.println(student1.toString());}session.commit();}@Testpublic void findAllStudent(){Integer pageSize=5;Integer pageIndex =1;Integer pageStart =pageSize *(pageIndex-1);List<student> students =mapper.findAllStudent(pageSize,pageStart);for(student student:students){System.out.println(student.toString());}}@Testpublic void findAllStudentByAge(){Integer pageSize=5;Integer pageIndex =1;student student=new student();Integer pageStart =pageSize *(pageIndex-1);student.setPageSize(pageSize);student.setName("博");student.setPageStart(pageStart);List<student> students =mapper.findAllStudentByAge(student);for(student student1:students){System.out.println(student1.toString());}}@Testpublic  void findUserByStudentName(){List<student> students=mapper.findUserByStudentName("%杨%");for(student student1:students){System.out.println(student1.toString());}}@Testpublic void findUser(){student student=new student();student.setSex("男");student.setPhone("1234321");student.setAge(11);student.setName("zzz");student.setPassword("123321");List<student> students=mapper.findUser(student);for(student student1:students){System.out.println(student1.toString());}}@Test
public void update(){student student=new student();student.setName("zzz");student.setId(2);student.setPassword("11441276423");student.setAge(143);student.setPhone("14231312");student.setSex("男");Integer num=mapper.update(student);List<student> students=mapper.findUser(student);for(student student1:students){System.out.println(student1.toString());}System.out.println(num);}@Test
public void selectUserByChoose(){student student=new student();student.setId(2);student.setName("bo");List<student>students=mapper.selectUserByChoose(student);for(student student1:students){System.out.println(student1.toString());}
}@Test
public  void  selectUserByUsernameAndSex(){student student=new student();student.setSex("男");student.setName("bo");List<student>students=mapper.selectUserByUsernameAndSex(student);for(student student1:students){System.out.println(student1.toString());}}@Test
public  void trimUpdate(){student student=new student();student.setName("sssssss");student.setId(2);mapper.trimUpdate(student);}@Testpublic void deleteMoreByArray(){Integer[] integer = new Integer[]{11,12,10,11};mapper.deleteMoreByArray(integer);session.commit();}@Testpublic void insertMoreByList(){student user1 = new student("小赵","男","1234",11);student user2 = new student("小张","男","122234",4);student user3 = new student("小李","男","123334",31);List<student> users = Arrays.asList(user1,user2,user3);mapper.insertMoreByList(users);session.commit();}}

单元测试基础

单元测试是验证代码最小单元(如函数、方法)行为的自动化测试。以下以Java的JUnit框架为例说明基本用法:

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;public class CalculatorTest {@Testpublic void testAddition() {Calculator calc = new Calculator();assertEquals(5, calc.add(2, 3));  // 验证2+3=5}
}

测试注解类型

  • @Test:标记方法为测试用例
  • @BeforeEach:每个测试前执行初始化
  • @AfterEach:每个测试后执行清理
  • @BeforeAll / @AfterAll:全局初始化和清理(静态方法)

断言方法示例

import static org.junit.jupiter.api.Assertions.*;assertTrue(result > 0);          // 验证条件为真
assertNull(someObject);          // 验证对象为空
assertArrayEquals(expected, actual); // 验证数组相等

参数化测试

通过@ParameterizedTest实现多组输入测试:

@ParameterizedTest
@ValueSource(ints = {1, 2, 3})
void testIsPositive(int number) {assertTrue(number > 0);
}

测试覆盖率

使用工具(如JaCoCo)统计代码被测试覆盖的比例,通常建议达到80%以上关键路径覆盖率。在Maven项目中配置示例:

<plugin><groupId>org.jacoco</groupId><artifactId>jacoco-maven-plugin</artifactId><version>0.8.7</version><executions><execution><goals><goal>prepare-agent</goal></goals></execution></executions>
</plugin>

 Arrays.asList

Arrays.asList 方法

Arrays.asList 是 Java 中 java.util.Arrays 类提供的一个静态方法,用于将数组或可变参数转换为一个固定大小的列表(List)。该方法返回的列表是基于原始数组的视图,因此对列表的修改会影响原始数组,反之亦然。

语法
public static <T> List<T> asList(T... a)

使用示例

以下是一些常见的 Arrays.asList 用法示例:

示例 1:将数组转换为列表
String[] stringArray = {"apple", "banana", "cherry"};
List<String> stringList = Arrays.asList(stringArray);
System.out.println(stringList); // 输出: [apple, banana, cherry]
示例 2:直接传递可变参数
List<String> list = Arrays.asList("one", "two", "three");
System.out.println(list); // 输出: [one, two, three]

注意事项

  1. 固定大小列表
    返回的列表是固定大小的,不能添加或删除元素,否则会抛出 UnsupportedOperationException

    List<String> list = Arrays.asList("a", "b", "c");
    list.add("d"); // 抛出 UnsupportedOperationException
    
  2. 修改会影响原始数组
    由于返回的列表是原始数组的视图,修改列表中的元素会影响原始数组。

    String[] arr = {"a", "b", "c"};
    List<String> list = Arrays.asList(arr);
    list.set(0, "x"); // 修改列表
    System.out.println(arr[0]); // 输出: x
    

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

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

相关文章

【Node.js】高级主题

个人主页&#xff1a;Guiat 归属专栏&#xff1a;node.js 文章目录 1. Node.js 高级主题概览1.1 高级主题架构图 2. 事件循环与异步编程深度解析2.1 事件循环机制详解事件循环阶段详解 2.2 异步编程模式演进高级异步模式实现 3. 内存管理与性能优化3.1 V8 内存管理机制内存监控…

冰箱热交换的原理以及如何加氟

冰箱如何加氟&#xff1a; 氟利昂被节流装置降压后&#xff0c;进入冰箱的蒸发器&#xff0c;此时它处于低温低压液态状态。在冰箱内部&#xff08;例如 0C 或 -10C&#xff09;&#xff1a;它很容易气化&#xff08;因为其沸点很低&#xff09;在气化过程中吸收周围热量。 1…

WordPress多语言插件安装与使用教程

WordPress多语言插件GTranslate的使用方法 在wordpress网站后台搜索多语言插件GTranslate并安装&#xff0c;安装完成、用户插件后开始设置&#xff0c;以下为设置方法&#xff1a; 1、先在后台左侧找到Gtranslate&#xff0c;进入到设置界面 2、选择要显示的形式&#xff0c…

DELL EMC PowerStore BBU更换手册

写在前面 上周给客户卖了一个BBU电池&#xff0c;客户要写一个更换方案。顺利完成了更换&#xff0c;下面就把这个更换方案给大家share出来&#xff0c;以后客户要写&#xff0c;您就Ctrlc 和Ctrlv就可以了。 下面的步骤是最理想的方式&#xff0c;中间没有任何的问题&#xff…

FastMCP:为大语言模型构建强大的上下文和工具服务

FastMCP&#xff1a;为大语言模型构建强大的上下文和工具服务 在人工智能快速发展的今天&#xff0c;大语言模型&#xff08;LLM&#xff09;已经成为许多应用的核心。然而&#xff0c;如何让这些模型更好地与外部世界交互&#xff0c;获取实时信息&#xff0c;执行特定任务&a…

CMake基础:CMakeLists.txt 文件结构和语法

目录 1.CMakeLists.txt基本结构 2.核心语法规则 3.关键命令详解 4.常用预定义变量 5.变量和缓存 6.变量作用域与传递 7.注意事项 1.CMakeLists.txt基本结构 CMakeLists.txt 是 CMake 构建系统的核心配置文件&#xff0c;采用命令式语法组织项目结构和编译流程。主要用于…

战略-2.1 -战略分析(PEST/五力模型/成功关键因素)

战略分析路径&#xff0c;先宏观&#xff08;PEST&#xff09;、再产业&#xff08;产品生命周期、五力模型、成功关键因素&#xff09;、再竞争对手分析、最后企业内部分析。 本文介绍&#xff1a;PEST、产品生命周期、五力模型、成功关键因素、产业内的战略群组 一、宏观环境…

深入理解设计模式:工厂模式、单例模式

深入理解设计模式&#xff1a;工厂模式、单例模式 设计模式是软件开发中解决常见问题的可复用方案。本文将详细介绍两种种重要的创建型设计模式&#xff1a;工厂模式、单例模式&#xff0c;并提供Java实现示例。 一、工厂模式 工厂模式是一种创建对象的设计模式&#xff0c;…

Jenkins 2.426.2配置“构建历史的显示名称,加上包名等信息“

Jenkins 2.426.2配置“构建历史的显示名称,加上包名等信息" 需求:想要在构建历史中展示,本次运行的是哪个版本或哪个包 操作步骤: 1、先安装插件Build Name and Description Setter 2、Set Build Name 3、构建历史处查看展示 插件特性说明 安装依赖:需手动安装 Build …

为何在VMware中清理CentOS虚拟机后,本地磁盘空间未减少的问题解决

文章目录 前言原因:虚拟机磁盘&#xff0c;到底是咋回事&#xff1f;为啥空间没变小&#xff1f; 解决方案 前言 在使用VMware运行CentOS虚拟机时&#xff0c;你是否曾遇到过这样的情况&#xff1a;明明在虚拟机内删除了大量文件&#xff0c;rm -rf 后发现并没什么用&#xff…

Development靶机通关笔记

一、主机发现 arp-scan -l靶机ip为192.168.55.152 二、端口扫描、目录枚举、漏洞扫描、指纹识别 2.1端口扫描 nmap --min-rate 10000 -p- 192.168.55.152发现靶机没有开放80端口&#xff0c;开放的是8080端口 UDP端口扫描 nmap -sU --min-rate 10000 -p- 192.168.55.152靶…

自然语言处理核心技术:词向量(Word Embedding)解析

自然语言处理核心技术&#xff1a;词向量&#xff08;Word Embedding&#xff09;全面解析 在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;如何让计算机理解人类语言的语义一直是核心挑战。词向量&#xff08;Word Vector&#xff09;&#xff0c;又称词嵌入&…

【Matlab】雷达图/蛛网图

文章目录 一、简介二、安装三、示例四、所有参数说明 一、简介 雷达图&#xff08;Radar Chart&#xff09;又称蛛网图&#xff08;Spider Chart&#xff09;是一种常见的多维数据可视化手段&#xff0c;能够直观地对比多个指标并揭示其整体分布特征。 雷达图以中心点为原点&…

Vue3实现轮播表(表格滚动)

在这之前,写过一篇Vue2实现该效果的博文:vue-seamless-scroll(一个简单的基于vue.js的无缝滚动) 有兴趣也可以去看下,这篇是用vue3实现,其实很简单,目的是方便后面用到直接复制既可以了。 安装: <

安卓开发用到的设计模式(1)创建型模式

安卓开发用到的设计模式&#xff08;1&#xff09;创建型模式 文章目录 安卓开发用到的设计模式&#xff08;1&#xff09;创建型模式1. 单例模式&#xff08;Singleton Pattern&#xff09;2. 工厂模式&#xff08;Factory Pattern&#xff09;3. 抽象工厂模式&#xff08;Abs…

后端开发概念

1. 后端开发概念解析 1.1. 什么是服务器&#xff0c;后端服务 1.1.1. 服务器 服务器是一种提供服务的计算机系统&#xff0c;它可以接收、处理和响应来自其他计算机系统&#xff08;客户端&#xff09;的请求。服务器主要用于存储、处理和传输数据&#xff0c;以便客户端可以…

Spring AI 源码解析:Tool Calling链路调用流程及示例

Tool工具允许模型与一组API或工具进行交互&#xff0c;增强模型功能&#xff0c;主要用于&#xff1a; 信息检索&#xff1a;从外部数据源检索信息&#xff0c;如数据库、Web服务、文件系统或Web搜索引擎等 采取行动&#xff1a;可用于在软件系统中执行特定操作&#xff0c;如…

Spyglass:跨时钟域同步(长延迟信号)

相关阅读 Spyglasshttps://blog.csdn.net/weixin_45791458/category_12828934.html?spm1001.2014.3001.5482 简介 长延迟信号方案用于控制或数据信号跨时钟域同步&#xff0c;该方案将使用quasi_static约束的跨时钟域信号视为已同步&#xff0c;如图1所示。 // test.sgdc q…

Linux云计算训练营笔记day13【CentOS 7 find、vim、vimdiff、ping、wget、curl、RPM、YUM】

Linux云计算训练营笔记day13[CentOS 7 find、vim、vimdiff、ping、wget、curl、RPM、YUM]] 目录 Linux云计算训练营笔记day13[CentOS 7 find、vim、vimdiff、ping、wget、curl、RPM、YUM]]1.find练习2.vim高级使用2.1 命令模式:2.2 插入模式:2.3 末行模式: 3. vimdiff4. ping5.…

网络流量分析工具ntopng的安装与基本使用

网络流量分析工具ntopng的安装与基本使用 一、ntopng基本介绍1.1 ntopng简介1.2 主要特点1.3 使用场景 二、本地环境介绍2.1 本地环境规划2.2 本次实践介绍 三、安装ntopng工具3.1 官网地址3.2 配置软件源3.3 添加软件源3.4 安装ntopng 四、ntopng的基本配置4.1 修改配置文件4.…