SpringBoot整合Mybatis-plus(一)基本使用与自定义模板代码生成器

2023-10-29


SpringBoot整合Mybatis-plus 代码生成以及基本使用(一)

本小章节学习内容是SpringBoot整合Mybatis-plus ,通过本文可以初步了解以及使用Mybatis-plus 以下简称mp ,掌握对mp代码生成器的使用(内置/自定义模板)

MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

一.所需依赖

依赖包含了阿里druid (数据库监控) mp 以及mp代码生成器和相关依赖 lombok 简化开发代码 数据库连接驱动等…

       <!--阿里数据库连接池 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.14</version>
        </dependency>
        <!--mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.3.1.tmp</version>
        </dependency>
        <!--myabtis-plus代码生成器-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.3.1.tmp</version>
        </dependency>
        <!--代码生成所需的模板依赖-->
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-engine-core</artifactId>
            <version>2.2</version>
        </dependency>
        <!--web支持-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

二.使用MybatisPlus需要配置什么

扫包

和mybatis一样 ,mp的使用也是需要扫包的(扫描Mapper接口)

在SpringBoot启动主程序上打上注解

@EnableTransactionManagement //开启事务管理
@MapperScan("com.leilei.mapper") //扫描包

配置的说明我已经在YML文件中详细的写了

yml配置
# 配置端口
server:
  port: 8081
spring:
  # 配置数据源
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mybatis-plus?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
    username: root
    password: root
    druid:
      # 初始连接数
      initialSize: 5
      # 最小连接池数量
      minIdle: 10
      # 最大连接池数量
      maxActive: 20
      # 配置获取连接等待超时的时间
      maxWait: 60000
      # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
      timeBetweenEvictionRunsMillis: 60000
      # 配置一个连接在池中最小生存的时间,单位是毫秒
      minEvictableIdleTimeMillis: 300000
      # 配置一个连接在池中最大生存的时间,单位是毫秒
      maxEvictableIdleTimeMillis: 900000
      # 配置检测连接是否有效
      validationQuery: SELECT 1 FROM DUAL
      testWhileIdle: true
      testOnBorrow: false
      testOnReturn: false
      webStatFilter:
        enabled: true
      statViewServlet:
        enabled: true
        # 设置白名单,不填则允许所有访问
        allow:
        url-pattern: /druid/*
        # 控制台管理用户名和密码
        login-username: leilei
        login-password: 123456
      filter:
        stat:
          enabled: true
          # 慢SQL记录
          log-slow-sql: true
          slow-sql-millis: 1000
          merge-sql: true
        wall:
          config:
            multi-statement-allow: true
# mybatis-plus相关配置
mybatis-plus:
  # xml扫描,多个目录用逗号或者分号分隔(告诉 Mapper 所对应的 XML 文件位置)
  mapper-locations: classpath:com/leilei/mapper/*/*Mapper.xml
  # 以下配置均有默认值,可以不设置
  global-config:
    db-config:
      #主键类型  auto:"数据库ID自增" 1:"用户输入ID",2:"全局唯一ID (数字类型唯一ID)", 3:"全局唯一ID UUID";
      id-type: auto
      #字段策略 IGNORED:"忽略判断"  NOT_NULL:"非 NULL 判断")  NOT_EMPTY:"非空判断"
      field-strategy: NOT_EMPTY
      #数据库类型
      db-type: MYSQL
  configuration:
    # 是否开启自动驼峰命名规则映射:从数据库列名到Java属性驼峰命名的类似映射
    map-underscore-to-camel-case: true
    # 如果查询结果中包含空值的列,则 MyBatis 在映射的时候,不会映射这个字段
    call-setters-on-nulls: true
    # 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
代码生成器配置

在本文中,我使用了mp代码生成器

Copy官网的代码生成器后我发现有一句代码,感觉一脸懵逼

String projectPath = System.getProperty("user.dir");

后续发现,此句是获取项目根目录的代码

代码生成相关的所有配置均可在CodeGenerator.class 中配置,当然,也可以编写一个xxx.properties文件 将所有统一的文件编写在其中,然后再CodeGenerator 读取这个文件即可,这样,我们就可以从修改代码,转向修改配置

本文中,我举例了将数据源以及作者 还有我们的工程父包路径内容写在了xxx.properties中

genreator.properties
#作者
author=leilei

#数据源
jdbc.username=root
jdbc.password=root
jdbc.url=jdbc:mysql://localhost:3306/mybatis-plus?serverTimezone=UTC&useUnicode=true&useSSL=false&characterEncoding=utf8

#包配置
parent=com.leilei
CodeGenerator
package com.leilei.generator;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
@Slf4j
public class CodeGenerator {

    public static void main(String[] args) throws InterruptedException {
        //项目根目录  不可修改
        String projectPath = System.getProperty("user.dir");
        log.info("项目根路径"+projectPath);
        //用来获取Mybatis-Plus.properties文件的配置信息
        ResourceBundle rb = ResourceBundle.getBundle("genreator");

        AutoGenerator mpg = new AutoGenerator();
        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        gc.setOutputDir(projectPath + "/src/main/java");
        gc.setFileOverride(true);
        // 开启 activeRecord 模式
        gc.setActiveRecord(true);
        // XML 二级缓存
        gc.setEnableCache(false);
        // XML ResultMap 映射图
        gc.setBaseResultMap(true);
        // XML columList
        gc.setBaseColumnList(false);
        gc.setAuthor(rb.getString("author"));
        mpg.setGlobalConfig(gc);

        // 数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setDbType(DbType.MYSQL);
        dsc.setTypeConvert(new MySqlTypeConvert());
        //注意Mysql 驱动版本问题 我这为8版本
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername(rb.getString("jdbc.username"));
        dsc.setPassword(rb.getString("jdbc.password"));
        dsc.setUrl(rb.getString("jdbc.url"));
        mpg.setDataSource(dsc);

        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
         /** 此处可以修改为您的表前缀,如果没有,注释掉即可*/
         //strategy.setTablePrefix(new String[] { "t_" });
        /** 表名生成策略*/
        strategy.setNaming(NamingStrategy.underline_to_camel);
        /** 需要生成的表*/
        strategy.setInclude(new String[]{"dept"});
        mpg.setStrategy(strategy);

        // 包配置
        PackageConfig pc = new PackageConfig();
        pc.setParent(rb.getString("parent"));
        pc.setController("controller");
        pc.setService("service");
        pc.setServiceImpl("service.impl");
        pc.setEntity("entity");
        pc.setMapper("mapper");
        mpg.setPackageInfo(pc);

        // 注入自定义配置,可以在 VM 中使用 cfg.abc 【可无】
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
            }
        };

        List<FileOutConfig> focList = new ArrayList<FileOutConfig>();

        // 调整 xml 生成目录演示
        focList.add(new FileOutConfig("/templates/mapper.xml.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {

                // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
                return projectPath + "/src/main/resources/com/leilei/mapper/" + tableInfo.getEntityName()
                        + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
            }
        });

        // 调整 query 生成目录
/*        focList.add(new FileOutConfig("/templates/query.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return rb.getString("OutputDomainDir")+ "/cn/leilei/query/" + tableInfo.getEntityName() + "Query.java";
            }
        });*/

        //调整 entity 生成目录
        focList.add(new FileOutConfig("/templates/entity.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return projectPath+ "/src/main/java/com/leilei/entity/" + tableInfo.getEntityName() + ".java";
            }
        });

        cfg.setFileOutConfigList(focList);
        mpg.setCfg(cfg);

        // 自定义模板配置,可以 copy 源码 mybatis-plus/src/main/resources/templates 下面内容修改,
        // 放置自己项目的 src/main/resources/templates 目录下, 默认名称一下可以不配置,也可以自定义模板名称
        TemplateConfig tc = new TemplateConfig();
        //tc.setController("/templates/controller.java.vm");
        // 如上任何一个模块如果设置 空 OR Null 将不生成该模块。
        tc.setEntity(null);
        tc.setXml(null);
        mpg.setTemplate(tc);
        // 执行生成
        mpg.execute();
    }
}

本项目是参照代码生成器源码修改了Controller ,编写了单表的CRUD ,直接生成即可接口测试,简化了很多单表接口的开发时间

附上我的Controller模板,本模板是使用了RestController ,所有接口返回值全是Json

注意: 模板中的import com.leilei.util.response.JsonReturn; 包路径是我项目中我自定义的统一json返回封装类

Controller模板
package ${package.Controller};

import ${package.Service}.${table.serviceName};
import ${package.Entity}.${entity};

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.leilei.util.response.JsonReturn;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * <p>
 *  ${table.entityPath}前端控制器  RestController注解 将结果以JSON形式返回
 * </p>
 *
 * @author leilei
 * @since ${date}
 */
@RestController
@RequestMapping("/${table.entityPath}")
public class ${entity}Controller {
    @Autowired
    public ${table.serviceName} ${table.entityPath}Service;

    /**
     * 保存修改公用 POST请求方式
     * @param ${table.entityPath} 修改或保存的对象
     * @return JsonReturn
     */
    @PostMapping("/save")
    public JsonReturn save(${entity} ${table.entityPath}) {
        if (${table.entityPath}.getId() != null){
            try {
                ${table.entityPath}Service.updateById(${table.entityPath});
                return JsonReturn.buildSuccess(${table.entityPath}, "操作成功");
            } catch (Exception e) {
                e.printStackTrace();
                return JsonReturn.buildFailure("操作失败" + e.getMessage());
            }
        }
        try {
            ${table.entityPath}Service.save(${table.entityPath});
            return JsonReturn.buildSuccess(${table.entityPath}, "操作成功");
        } catch (Exception e) {
            e.printStackTrace();
            return JsonReturn.buildFailure("操作失败" + e.getMessage());
        }

    }

    /**批量删除 支持POST GET
     * @param ids Long 类型 List 集合
     * @return JsonReturn
     */
    @RequestMapping("remove")
    public JsonReturn delete(@RequestBody List<Long> ids) {
        try {
            ${table.entityPath}Service.removeByIds(ids);
            return JsonReturn.buildSuccess(ids, "操作成功");
        } catch (Exception e) {
            e.printStackTrace();
            return JsonReturn.buildFailure("操作失败" + e.getMessage());
        }
    }

    /**
     * 查询一个  支持POST GET
     *
     * @param id 查找对象的主键ID
     * @return JsonReturn
     */
    @RequestMapping("findOne")
    public JsonReturn findOne(Long id) {
        try {
            ${entity} ${table.entityPath} = ${table.entityPath}Service.getById(id);
            return JsonReturn.buildSuccess(${table.entityPath}, "操作成功");
        } catch (Exception e) {
            e.printStackTrace();
            return JsonReturn.buildFailure("操作失败" + e.getMessage());
        }
    }


    /**查询所有 支持POST GET ,未传当前页以及分页长度 则默认1页 10条数据
     * @param pageNum 当前页
     * @param pageSize 每页最大数据数
     * @return JsonReturn
     */
    @RequestMapping("findAll")
    public JsonReturn findAll(Integer pageNum, Integer pageSize) {

        if (pageNum != null && pageSize != null) {
            try {
                Page<${entity}> page = ${table.entityPath}Service.page(new Page<${entity}>(pageNum, pageSize));
                return JsonReturn.buildSuccess(page, "操作成功");
            } catch (Exception e) {
                e.printStackTrace();
                return JsonReturn.buildFailure("操作失败" + e.getMessage());
            }
        }
        try {
            Page<${entity}> page = ${table.entityPath}Service.page(new Page<>());
            return JsonReturn.buildSuccess(page, "操作成功");
        } catch (Exception e) {
            e.printStackTrace();
            return JsonReturn.buildFailure("操作失败" + e.getMessage());
        }
    }
}

那么到这里 mp的数据源配置 druid 监控 以及Mp强大的代码生成器就完成了

代码生成只要运行CodeGenerator 中的Main 方法即可生成了!!!!!!

在这里插入图片描述

三.mp的基本使用

mp内提供了大量的方法 很多单表的查询方法都已经帮我们封装好了

mp中方法使用的详细教程

查询所有
    @Test
    void contextLoads() {
        userService.list().forEach(e -> System.out.println(e));
        roleService.list().forEach(e -> System.out.println(e));
    }
分页

使用Mp分页需要一个配置类 (别想太多 ,从官网Copy来的,当然也还有其他方式进行分页)

/**
 * @author leilei
 * Spring boot方式 -Mybatis-plus 分页
 */
@Configuration
public class MybatisPlusConfig {

    @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求  默认false
        paginationInterceptor.setOverflow(false);
        // 设置最大单页限制数量,默认 500 条,-1 不受限制
        paginationInterceptor.setLimit(500);
        // 开启 count 的 join 优化,只针对部分 left join
        paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
        return paginationInterceptor;
    }
}

单表分页查询

    @Test
    public void testPage() {
        Page<RealEseate> realEseatePage = realEseateService.page(new Page<RealEseate>(1, 5), new QueryWrapper<RealEseate>().orderByDesc("build_time"));
        realEseatePage.getRecords().forEach(e -> System.out.println(e));
        System.out.println(realEseatePage.getTotal());

    }
Mybatis-plus 中LocalDateTime字段 查询报错

在测试 realEseateService.page()发现报错

在这里插入图片描述报错意思很明显 ,build_time字段获取出错

我记得很清楚,在一开始我并未配置Druid 的时候,没有报错的,并且我也查看了实体类中是一个LocalDateTime字段,并且也是提供了GET SET 方法的,怎么会获取不到,难道是Druid问题???

我百度了很久 有人说是Druid版本问题,需要升级版本, 于是我提升Druid 到了 1.1.19 ,并未解决

惊了 难道是mp与Druid 有问题?

经过我不断的修改以及网上查找资料降mp版本 改字段等等,终于找到了解决办法!!!!

解决办法

方法1.降低mp版本

由于我mp 版本使用的最新版,为3.3.1 当我不断重试 降mp 版本为3.1.0后 发现并无报错

方法2.修改字段类型,不降mp与Druid版本

改变时间相关的实体类字段类型, LocalDateTime 修改为Date 类型

最后测试
在这里插入图片描述

连表查询

mp中连表也是得和mybatis中一样,在mpper.xml中编写sql 或者 mapper 接口中编写sql

    @Override
    public IPage selectJoinTablePage(Integer page, Integer size, String query) {
        Page<RealEseate> realEseatePage = new Page<>(page, size);

        return realEseateMapper.selectJoinTablePage(realEseatePage, query);
    }
 <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="com.leilei.entity.RealEseate">
        <id column="id" property="id" />
        <result column="project_name" property="projectName" />
        <result column="address" property="address" />
        <result column="house_type" property="houseType" />
        <result column="area" property="area" />
        <result column="build_time" property="buildTime" />
        <result column="user_id" property="userId" />
        <result column="uid" property="user.id"/>
        <result column="uname" property="user.username"/>
        <result column="upwd" property="user.password"/>
    </resultMap>
    
    
    <select id="selectJoinTablePage" resultMap="BaseResultMap">
        select re.*,u.id uid ,u.username uname,u.password upwd from user u join real_eseate re on u.id = re.user_id
        <where>
            <if test="query!=null and query!=''">
                and u.username=#{query};
            </if>
        </where>
    </select>

QueryWrapper条件构造的使用

详细使用请戳官网,本文仅仅只是展示几个。。。MyBatis-Plus条件构造

Test
    public void testWrapper() {
        /**
         * 比较 大于小于 等于 between 排序.....
         */
        //SELECT id,permission_name,permission_sn FROM permission WHERE (permission_name = ?)
        System.out.println(permissionService.getOne(new QueryWrapper<Permission>().eq("permission_name", "支付管理")));

        //SELECT id,permission_name,permission_sn FROM permission WHERE (id > ? AND id < ? AND permission_sn = ?)
        System.out.println(permissionService.getOne(new QueryWrapper<Permission>()
                .gt("id", 1)
                .lt("id", 3)
                .eq("permission_sn", "pro")));

        //SELECT id,project_name,address,house_type,area,build_time,user_id FROM real_eseate ORDER BY build_time DESC
        realEseateService.list(new QueryWrapper<RealEseate>().orderByDesc("build_time")).forEach(e -> System.out.println(e));

        //SELECT id,project_name,address,house_type,area,build_time,user_id FROM real_eseate WHERE (id BETWEEN ? AND ?) LIMIT ?,?
        Page<RealEseate> realEseatePage = realEseateService.page(new Page<RealEseate>(1, 3),
                                                                 new QueryWrapper<RealEseate>().between("id", 1, 5));

    }

批量操作

@Test
    public void testBatch() {
        /**
         * 新增
         */
        //==>  Preparing: INSERT INTO role ( role_name ) VALUES ( ? )
        //==> Parameters: 驱蚊器翁(String)
        //==> Parameters: 俺问问去(String)
        roleService.saveBatch(Arrays.asList(new Role("驱蚊器翁"), new Role("俺问问去")));
        /**
         *批量修改或者插入  有Id 则修改 无则新增  可传Wrapper
         */
        roleService.saveOrUpdateBatch(Arrays.asList(new Role(3L, "璀璨钻石"), new Role(4L, "尊贵铂金")));
    }
一对多

sql 使用join进行连表

    <select id="selectOneDetailByReal" resultMap="twoResultMap">
        select  u.id, u.username, u.password,re.id rid,re.project_name rproname,
        re.house_type rhouse,re.address raddress,re.area rarea,re.build_time rtime
        from user u join real_eseate re on u.id = re.user_id
        where u.id=#{userid}
    </select>

映射

 <!-- 一对多查询映射结果 -->
    <resultMap id="twoResultMap" type="com.leilei.entity.User">
        <id column="id" jdbcType="BIGINT"  property="id" />
        <result column="username" jdbcType="VARCHAR" property="username" />
        <result column="password" jdbcType="VARCHAR" property="password" />
        <!--关联对象 房产-->
        <!--一对多方式一-->
        <collection property="realEseateList" ofType="com.leilei.entity.RealEseate">
            <id column="rid" jdbcType="BIGINT" property="id"/>
            <result column="rproname" jdbcType="VARCHAR" property="projectName"/>
            <result column="raddress" jdbcType="VARCHAR" property="address"/>
            <result column="rhouse" jdbcType="VARCHAR" property="houseType"/>
            <result column="rarea" jdbcType="INTEGER" property="area"/>
            <result column="rtime" jdbcType="TIMESTAMP" property="buildTime"/>
        </collection>
    </resultMap>
多对多-多对多 多层嵌套映射查询

在本文中,我编写了一个用户-角色(多对多) 角色-权限(多对多)的一个情况

由于我是以用户为第一查询视角的 那用户角色 多对多中 在用户实体类中就需要一个 List<角色> roleList类型的字段来存储多个角色 在角色中呢 ,又需要 List<权限> permissionList 类型的字段来存储多个权限 ,并在通用映射结果中进行嵌套渲染 层层嵌套

sql 不使用join 进行连表

    <select id="selectOneDetail" resultMap="BaseResultMap">
        select distinct u.id,u.username,u.password,r.id roleId,r.role_name roleName,p.id perId,p.permission_name perName,p.permission_sn perSn
        from user u,user_role ur ,role r,role_permission rp ,permission p
        where ur.user_id=u.id and ur.role_id=r.id
        and rp.role_id=r.id and rp.permission_id=p.id
         and u.id=#{uid}
    </select>

映射

    <!-- 多对多查询映射结果 -->
    <resultMap id="BaseResultMap" type="com.leilei.entity.User">
        <id column="id" property="id" />
        <result column="username" property="username" />
        <result column="password" property="password" />
        <!--关联对象 角色-->
        <collection property="roleList" javaType="list" ofType="com.leilei.entity.Role">
            <id column="roleId" property="id"/>
            <result column="roleName" property="roleName"/>
            <!--内嵌关联  权限-->
            <collection property="permissionList" javaType="list" ofType="com.leilei.entity.Permission">
                <id column="perId" jdbcType="BIGINT" property="id"/>
                <result column="perName" jdbcType="VARCHAR" property="permissionName"/>
                <result column="perSn" jdbcType="VARCHAR" property="permissionSn"/>
            </collection>
        </collection>
    </resultMap>

在这里插入图片描述

爆红是因为本映射是以User 为第一视角 User类中并未包含 permissionList字段 所以爆假红 但是,在编写数据库了映射到实体中字段有响应代码提示时 则说明,是没有问题的
查询用户1 他对应的是两个角色 一个角色包含三个权限 一个角色包含两个权限
在这里插入图片描述
Druid监控
账户密码使用yml中针对由于Druid的配置
在这里插入图片描述
在这里插入图片描述
那么本文到这里就结束了,附上源码SpringBoot-Mybatis-plus

下一篇我准备整合SpringBoot-Mybatis-plus 多数据源

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SpringBoot整合Mybatis-plus(一)基本使用与自定义模板代码生成器 的相关文章

随机推荐

  • 什么是webSocket?

    什么是webSocket WebSockets是一种协议 它允许在Web应用程序中建立持久连接 这意味着当客户端与服务器建立连接后 它们可以始终保持连接状态 直到其中一个终止连接 相比于传统的HTTP协议 WebSockets提供了更高效的
  • git rev-parse --git-dir的使用

    如果某次修改仅仅改动几个字 不想重新生成一条记录的话 可以在git add 之后执行git commit amend命令 但是执行git commit amend不生成新的目录的前提是配置hook 也就是需要用到git rev parse
  • 2021-04-14

    eslint 自动修复 现在写项目一般都要用到eslint规范代码格式 但是在开发阶段要时刻注意空格 缩进 分号也是挺影响效率的 所以需要用eslint 的自动修复命令 在package json中的命令 lint eslint ext j
  • 网络安全通识全解

    01 什么是区块链 区块链 Blockchain 是指通过去中心化和去信任的方式集体维护一个可靠数据库的技术方案 从本质上讲 它是一个共享数据库 存储于其中的数据或信息 具有 不可伪造 全程留痕 可以追溯 公开透明 集体维护 等特征 是一种
  • 成功解决keil识别不到单片机芯片,下载不了程序

    成功解决keil识别不到单片机芯片 下载不了程序 我的芯片是STM32F429 正点原子的阿波罗 今天使用开发板做实验 突然找不到芯片了 以前下载的PWM波也运行不了 查找了好久 原来是芯片锁了 终于解决了 我是第二种办法实现给芯片解锁的
  • 网络安全等保:Oracle数据库测评

    以下结果以Oracle 11g为例 通过PL SQL进行管理 未进行任何配置 按照等保2 0标准 2021报告模板 三级系统要求进行测评 一 身份鉴别 a 应对登录的用户进行身份标识和鉴别 身份标识具有唯一性 身份鉴别信息具有复杂度要求并定
  • MySQL之体系结构

    一 MySQL系统体系结构 1 MySQL系统体系结构 1 1 数据库 1 2 数据库实例 1 3 MySQL体系结构 1 4 逻辑存储结构 1 5 MySQL物理存储结构 二 MySQL主要文件 1 慢查询日志 1 1 慢查询日志相关参数
  • 电路基础(4) 电阻电路的一般分析

    1 电路的图 将上面的电路图 抛开其中元器件的性质 可以提取出 只有线和结点的图 如果考虑电流等的流向 则可以变化位 有向图 提取的有向图少了8那条支路 是因为把元件的并联组合也作为一条支路了 提取的有向图少了7那条支路 是因为把元件的串联
  • Janus网关的集成与优化

    本文由学霸君音视频架构师李桥平在LiveVideoStackCon 2020 线上峰会的演讲内容整理而成 内容主要包括Janus网关的集成过程以及集成过程中遇到的一些问题 文 李桥平 整理 LiveVideoStack 大家好 我是李桥平
  • 群晖NAS公网访问(IP+DNSPOD+桥接+端口转发+DDNS+WebDAV)

    群晖NAS公网访问 IP DNSPOD 桥接 端口转发 DDNS WebDAV 文章更新一版 结果审核不过 只能转载了 https www cnblogs com nomil9 articles 12924354 html
  • 从工厂到五星级写字楼,我从5K涨到了12K,中间只隔了一个python

    写在开篇 我大学是计算机专业的 但是我对于代码方面不太感冒 实习的时候接触到UI设计还挺感兴趣 也会有一些培训机构来学校做一些宣讲 但是家里面不太支持 他们就会觉得大学四年也差不多是花这些你都没有学到什么 你现在花一两万块钱去学这四个月 难
  • abp OFFSET 附近有语法错误。 在 FETCH 语句中选项 NEXT 的用法无效。

    在学习abp框架时 出现上述错误 这是因为使用了sql server2008 数据库造成端 数据库版本低 可以更改代码 在项目中ctrl f搜索 UseSqlServer 找到如下代码 添加 b gt b UseRowNumberForPa
  • 毕业设计-BP神经网络的房地产价值评估研究

    目录 前言 课题背景和意义 实现技术思路 实现效果图样例 前言 大四是整个大学期间最忙碌的时光 一边要忙着备考或实习为毕业后面临的就业升学做准备 一边要为毕业设计耗费大量精力 近几年各个学校要求的毕设项目越来越难 有不少课题是研究生级别难度
  • virtualbox下以nat模式设置一个稳定的局域网,并通过远程连接工具如mobaXterm连接到其中

    文章目录 软件 虚拟机NAT网络布置过程 设置端口转发为mobaxterm连接做准备 mobaxterm中的session设置 又附一些感悟 软件 virtualbox7 0 2版本 centos7 虚拟机NAT网络布置过程 由于这个版本的
  • 一文讲懂:已上架APP如何换公司的各项主体-苹果、安卓、支付、域名等

    目录 前言 一 换支付宝支付 01 注册支付宝账号 02 企业认证 03 入驻开放平台 04 创建应用 05 商户产品签约 APP支付 06 商户产品签约 手机网站支付 07 商户产品签约 电脑网站支付 08 支付宝客户服务支持 二 换微信
  • double等浮点数比较问题,eps

    ACM中的浮点数精度处理 在ACM中 精度问题非常常见 其中计算几何头疼的地方一般在于代码量大和精度问题 代码量问题只要平时注意积累模板一般就不成问题了 精度问题则不好说 有时候一个精度问题就可能成为一道题的瓶颈 让你debug半天都找不到
  • RocksDB性能测试

    1 打开数据库 2 随机写 3 顺序写 4 查找 5 写入内容一定要char 么 是否支持其他数据结构 list map 等 6 写入少量数据没有生成stable 写入大量数据后生成stable即SST文件 怎么控制的 为什么写日志速度快
  • ifrme嵌入外部页面,在外部页面调用本页面方法,window.postMessage实现跨域通信

    项目场景 vue页面开发的系统要继承外部系统页面 并且在外部系统页面调用本系统的方法 这样来看的话肯定会存在跨域的问题 而且直接调用方法的话 也不太安全 后来了解到window postMessage实现跨域通信 所以想着根据通信信息来去实
  • 路由与交换技术-19-HSRP+PVSTP综合实验

    HSRP PVSTP 综合实验 目的 实现冗余和负载 用于多生成树 多个vlan 多生成树指定vlan的根交换机 阻塞指定端口 实现链路负载均衡 HRSP通过设置不同vlan的活跃路由和备份路由 实现vlan 10 vlan 20的虚拟路由
  • SpringBoot整合Mybatis-plus(一)基本使用与自定义模板代码生成器

    文章目录 一 所需依赖 二 使用MybatisPlus需要配置什么 扫包 yml配置 代码生成器配置 genreator properties CodeGenerator Controller模板 三 mp的基本使用 查询所有 分页 Myb