核心业务2:借款人申请借款额度

news2025/1/25 4:38:11

核心业务2:借款人申请借款额度

1.业务流程图

------------截止提交个人信息部分--------

2.借款人申请借款额度数据库设计

3.借款人申请额度流程

4.前端代码逻辑

5.后端代码逻辑

------------截止提交个人信息部分--------

核心业务2:借款人申请借款额度

1.业务流程图

在这里插入图片描述

①用户在注册登陆账户绑定之后,点击立即借款进入到借款认证页

  • A进入到借款认证页后,进入尚融宝判断借款状态来显示步骤
  • B表单中的下拉列表数据在尚融宝查询数据字典获取
  • C在上传照片时利用尚融宝上传数据到aliyun,在删除图片后删除aliyun中数据
  • D点击提交后提交表单到尚融宝更新借款人数据
    在这里插入图片描述

②如果A中已提交未审核则进入审核页

在这里插入图片描述

③如果A中已审核则将结果返回

在这里插入图片描述

2.借款人申请借款额度数据库设计

①用户数据表user_info

在这里插入图片描述

②借款人表borrower

在这里插入图片描述

③借款人绑定表borrower_attach

在这里插入图片描述

④三张表关系

  • user_info通过user_id和borrower的user_id关联
  • borrower的id和borrower_attach的borrow_id关联
  • user_info即如果用户为借款人申请借款额度,用户信息表中包含了该用户为借款人的认证状态。
  • borrower即包含了用户为借款人的基本信息
  • borrower_attach表包含了用户为借款人的四张图片信息(房产证,轿车证,身份证正反面)

3.借款人申请额度流程

①前端

  • 用户注册登陆绑定数据后
  • 第一次借款认证填写信息提交表单
  • 提交后再次访问提交表单页则直接进入认证中或者认证结果

②尚融宝后端

  • 用户访问认证页
  • 判断用户是否认证过,认证的状态。
  • 如果没有认证过则前端显示表单页,后端需要在表单页显示时返回数据字典来初始化表单的下拉列表。
  • 在填写表单时对图片的上传和删除同步到aliyun的oss
  • 在填写完表单之后前端提交表单,后端根据表单数据更新user_info的借款人认证状态,根据token获得user_id以及表单信息来更新borrower和borrower_attach

4.代码逻辑

①前端对应表单对象

在这里插入图片描述

②前端请求接口

  • 判断借款人认证状态
    在这里插入图片描述
  • 请求获取数据字典

在这里插入图片描述

  • 请求上传和删除图片
    在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • 提交表单
    在这里插入图片描述

③前端复杂逻辑

  • 需要完善表单信息。
    文件的表单信息需要上传成功后加入到表单中,如果删除文件,对应的也需要删除表单中的文件(删除文件如果删除表单,组件封装了调用成功后的响应结果)
  • 刚进入认证页会先进入表单页再判断是否认证过,前端就算认证过也会闪过表单。
    修改步骤为null,必须查看认证结果后赋值,不会闪表单

④总体代码

  • pages/user/borrow.vue
<template>
  <div class="personal-main">
    <div class="personal-pay">
      <h3><i>借款人信息认证</i></h3>

      <!--步骤导航-->
      <el-steps :active="active" style="margin: 40px">
        <el-step title="填写借款人信息"></el-step>
        <el-step title="提交平台审核"></el-step>
        <el-step title="等待认证结果"></el-step>
      </el-steps>

      <!--第一步-->
      <div v-if="active === 0" class="user-borrower">
        <!--个人信息-->
        <h6>个人基本信息</h6>
        <el-form label-width="120px">
          <el-form-item label="年龄">
            <el-col :span="5">
              <el-input v-model="borrower.age" />
            </el-col>
          </el-form-item>

          <el-form-item label="性别">
            <el-select v-model="borrower.sex">
              <el-option :value="1" :label="'男'" />
              <el-option :value="0" :label="'女'" />
            </el-select>
          </el-form-item>
          <el-form-item label="婚否">
            <el-select v-model="borrower.marry">
              <el-option :value="true" :label="'是'" />
              <el-option :value="false" :label="'否'" />
            </el-select>
          </el-form-item>
          <el-form-item label="学历">
            <el-select v-model="borrower.education">
              <el-option
                v-for="item in educationList"
                :key="item.value"
                :label="item.name"
                :value="item.value"
              />
            </el-select>
          </el-form-item>
          <el-form-item label="行业">
            <el-select v-model="borrower.industry">
              <el-option
                v-for="item in industryList"
                :key="item.value"
                :label="item.name"
                :value="item.value"
              />
            </el-select>
          </el-form-item>
          <el-form-item label="月收入">
            <el-select v-model="borrower.income">
              <el-option
                v-for="item in incomeList"
                :key="item.value"
                :label="item.name"
                :value="item.value"
              />
            </el-select>
          </el-form-item>
          <el-form-item label="还款来源">
            <el-select v-model="borrower.returnSource">
              <el-option
                v-for="item in returnSourceList"
                :key="item.value"
                :label="item.name"
                :value="item.value"
              />
            </el-select>
          </el-form-item>
        </el-form>
        <!--联系人信息-->
        <h6>联系人信息</h6>
        <el-form label-width="120px">
          <el-form-item label="联系人姓名">
            <el-col :span="5">
              <el-input v-model="borrower.contactsName" />
            </el-col>
          </el-form-item>
          <el-form-item label="联系人手机">
            <el-col :span="5">
              <el-input v-model="borrower.contactsMobile" />
            </el-col>
          </el-form-item>
          <el-form-item label="联系人关系">
            <el-select v-model="borrower.contactsRelation">
              <el-option
                v-for="item in contactsRelationList"
                :key="item.value"
                :label="item.name"
                :value="item.value"
              />
            </el-select>
          </el-form-item>
        </el-form>
        <!--身份认证信息-->
        <h6>身份认证信息</h6>
        <!--其中的module是为了区分每个上传文件的位置在OSS-->
        <el-form label-width="120px">
          <el-form-item label="身份证人像面">
            <el-upload
              :on-success="onUploadSuccessIdCard1"
              :on-remove="onUploadRemove"
              :multiple="false"
              :action="uploadUrl"
              :data="{ module: 'idCard1' }"
              :limit="1"
              list-type="picture-card"
            >
              <i class="el-icon-plus"></i>
            </el-upload>
          </el-form-item>
          <el-form-item label="身份证国徽面">
            <el-upload
              :on-success="onUploadSuccessIdCard2"
              :on-remove="onUploadRemove"
              :multiple="false"
              :action="uploadUrl"
              :data="{ module: 'idCard2' }"
              :limit="1"
              list-type="picture-card"
            >
              <i class="el-icon-plus"></i>
            </el-upload>
          </el-form-item>
        </el-form>
        <!--其他信息-->
        <h6>其他信息</h6>
        <el-form label-width="120px">
          <el-form-item label="房产信息">
            <el-upload
              :on-success="onUploadSuccessHouse"
              :on-remove="onUploadRemove"
              :multiple="false"
              :action="uploadUrl"
              :data="{ module: 'house' }"
              list-type="picture-card"
            >
              <i class="el-icon-plus"></i>
            </el-upload>
          </el-form-item>
          <el-form-item label="车辆信息">
            <el-upload
              :on-success="onUploadSuccessCar"
              :on-remove="onUploadRemove"
              :multiple="false"
              :action="uploadUrl"
              :data="{ module: 'car' }"
              list-type="picture-card"
            >
              <i class="el-icon-plus"></i>
            </el-upload>
          </el-form-item>
        </el-form>

        <el-form label-width="120px">
          <el-form-item>
            <el-button
              type="primary"
              :disabled="submitBtnDisabled"
              @click="save"
            >
              提交
            </el-button>
          </el-form-item>
        </el-form>
      </div>
      <!--第二步-->
      <div v-if="active === 1">
        <div style="margin-top:40px;">
          <el-alert
            title="您的认证申请已成功提交,请耐心等待"
            type="warning"
            show-icon
            :closable="false"
          >
            我们将在2小时内完成审核,审核时间为周一至周五8:0020:00</el-alert>
        </div>
      </div>
      <!--第三步-->
      <div v-if="active === 2">
        <div style="margin-top:40px;">
          <el-alert
            v-if="borrowerStatus === 2"
            title="您的认证审批已通过"
            type="success"
            show-icon
            :closable="false"
          >
          </el-alert>

          <el-alert
            v-if="borrowerStatus === -1"
            title="您的认证审批未通过"
            type="error"
            show-icon
            :closable="false"
          >
          </el-alert>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  data() {
    let BASE_API = process.env.BASE_API

    return {
      //为什么不设置为0?
      //因为只有当判断完成用户的认证状态才能确定在哪一步,如果写0的话如果用户状态为待审核由于ajax异步操作,会闪一下第一个列表
      active: null, //步骤
      borrowerStatus: null, //认证状态
      submitBtnDisabled: false, //提交按钮的修饰,防止表单重复提交,点击save然后不能提交
      //借款人信息
      borrower: {
        borrowerAttachList: [], //存储文件数据的基本信息
      },
      educationList: [], //学历列表
      industryList: [], //行业列表
      incomeList: [], //月收入列表
      returnSourceList: [], //还款来源列表
      contactsRelationList: [], //联系人关系
      uploadUrl: BASE_API + '/api/oss/file/upload', //文件上传地址
    }
  },

  methods: {
    //保存表单提交的信息
    save() {
      // debugger
      this.submitBtnDisabled = true
      this.$axios
        .$post('/api/core/borrower/auth/save', this.borrower)
        .then((response) => {
          this.active = 1
        })
    },
    //根据上传文件得到的结果,封装borrowerAttachList存储文件的基本信息(响应结果,文件参数)
    onUploadSuccessIdCard1(response, file) {
      this.onUploadSuccess(response, file, 'idCard1')
    },

    onUploadSuccessIdCard2(response, file) {
      this.onUploadSuccess(response, file, 'idCard2')
    },

    onUploadSuccessHouse(response, file) {
      this.onUploadSuccess(response, file, 'house')
    },

    onUploadSuccessCar(response, file) {
      this.onUploadSuccess(response, file, 'car')
    },

    onUploadSuccess(response, file, type) {
      // debugger
      if (response.code !== 0) {
        //上传失败,返回响应结果
        this.$message.error(response.message)
        return
      }
      // 上传成功,填充上传文件列表
      this.borrower.borrowerAttachList.push({
        imageName: file.name,
        imageUrl: response.data.url,
        imageType: type,
      })
      //console.log(this.borrower.borrowerAttachList)
    },

    //将oss系统删除文件(文件参数)file参数组装了上传的响应结果
    onUploadRemove(file, fileList) {
      console.log('file', file)
      console.log('fileList', fileList)
      //删除oss服务器上的内容
      //调用远程的删除接口
      this.$axios
        .$delete('/api/oss/file/remove?url=' + file.response.data.url)
        .then((response) => {
          // debugger
          console.log('远程删除文件成功')
          //从 this.borrower.borrowerAttachList列表中删除该文件
          //将过滤的结果回填到原来列表
          this.borrower.borrowerAttachList = this.borrower.borrowerAttachList.filter(
            function(item) {
              console.log('item', item)
              //两个地址相等则返回true,不删除
              return item.imageUrl != file.response.data.url
            }
          )
        })
    },

    //根据查询的数据字典初始化下拉列表
    initSelected() {
      //学历列表
      this.$axios
        .$get('/api/core/dict/findByDictCode/education')
        .then((response) => {
          this.educationList = response.data.dictList
        })

      //行业列表
      this.$axios
        .$get('/api/core/dict/findByDictCode/industry')
        .then((response) => {
          this.industryList = response.data.dictList
        })

      //收入列表
      this.$axios
        .$get('/api/core/dict/findByDictCode/income')
        .then((response) => {
          this.incomeList = response.data.dictList
        })

      //还款来源列表
      this.$axios
        .$get('/api/core/dict/findByDictCode/returnSource')
        .then((response) => {
          this.returnSourceList = response.data.dictList
        })

      //联系人关系列表
      this.$axios
        .$get('/api/core/dict/findByDictCode/relation')
        .then((response) => {
          this.contactsRelationList = response.data.dictList
        })
    },
    getUserInfo() {
      this.$axios
        .$get('/api/core/borrower/auth/getBorrowerStatus')
        .then((response) => {
          this.borrowerStatus = response.data.borrowerStatus

          if (this.borrowerStatus == 0) {
            //未认证,展示下拉列表
            this.active = 0
            this.initSelected()
          } else if (this.borrowerStatus == 1) {
            //审批中
            this.active = 1
          } else if (this.borrowerStatus == 2) {
            //审批通过
            this.active = 2
          } else if (this.borrowerStatus == -1) {
            //审批没通过
            this.active = 2
          }
        })
    },
  },

  created() {
    //更改为判断借款状态
    this.getUserInfo()
  },
}
</script>

5.后端代码逻辑

①前端调用的接口

  • 开发接口
    在这里插入图片描述
  • 调用的接口
    在这里插入图片描述

②后端复杂逻辑

  • 获取下拉列表时根据dict_code去查对应的子节点
    需要先查询到dict_code的id然后根据此id去查父id为此id的数据返回(调用之前写的根据父id查询的service)
  • 保存存款人信息时需要获取user_id绑定
    即需要用户先登录,此时可以从token中解析出user_id
  • 根据表单信息更新借款人表单时
    需要先根据user_id查询出user_info的基本信息,补充表单信息更新borrower表
  • 根据表单信息更新借款人附件表单时
    需要先查询借款人的id然后在附件表单中绑定借款人id
  • 提交表单后也需要更新user_info的借款人认证状态
  • 获取借款人认证状态
    可以从已登录的token中获取。然后根据id从borrower表中查询status,查询出数据则说明不是未认证返回status(1认证中2认证成功-1认证失败),查询不出数据则是未认证返回status(0未认证)

③后端创建的接受前端对象

package com.atguigu.srb.core.pojo.vo;

import com.atguigu.srb.core.pojo.entity.BorrowerAttach;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.util.List;

@Data
@ApiModel(description="借款人认证信息")
public class BorrowerVO{

    @ApiModelProperty(value = "性别(1:男 0:女)")
    private Integer sex;

    @ApiModelProperty(value = "年龄")
    private Integer age;

    @ApiModelProperty(value = "学历")
    private Integer education;

    @ApiModelProperty(value = "是否结婚(1:是 0:否)")
    private Boolean marry;

    @ApiModelProperty(value = "行业")
    private Integer industry;

    @ApiModelProperty(value = "月收入")
    private Integer income;

    @ApiModelProperty(value = "还款来源")
    private Integer returnSource;

    @ApiModelProperty(value = "联系人名称")
    private String contactsName;

    @ApiModelProperty(value = "联系人手机")
    private String contactsMobile;

    @ApiModelProperty(value = "联系人关系")
    private Integer contactsRelation;

    @ApiModelProperty(value = "借款人附件资料")
    private List<BorrowerAttach> borrowerAttachList;
}

④获取数据字典业务

  • controller
package com.atguigu.srb.core.controller.api;


import com.atguigu.common.result.R;
import com.atguigu.srb.core.pojo.entity.Dict;
import com.atguigu.srb.core.service.DictService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.List;

@Api(tags = "数据字典")
@RestController
@RequestMapping("/api/core/dict")
@Slf4j
public class DictController {

    @Resource
    private DictService dictService;

    @ApiOperation("根据DictCode获取下级节点")
    @GetMapping("/findByDictCode/{dictCode}")
    public R findByDictCode(
            @ApiParam("节点编码")
            @PathVariable("dictCode") String dictCode){

        List<Dict> list =  dictService.findByDictCode(dictCode);
        return R.ok().data("dictList",list);

    }
}

  • service(前三种方法是admin管理系统调用的Dict方法)
package com.atguigu.srb.core.service;

import com.atguigu.srb.core.pojo.dto.ExcelDictDTO;
import com.atguigu.srb.core.pojo.entity.Dict;
import com.baomidou.mybatisplus.extension.service.IService;

import java.io.InputStream;
import java.util.List;

/**
 * <p>
 * 数据字典 服务类
 * </p>
 *
 * @author Likejin
 * @since 2023-04-09
 */
public interface DictService extends IService<Dict> {


    void importData(InputStream inputStream);

    List<ExcelDictDTO> listDictData();

    List<Dict> listByParentId(Long parentId);

    /**
     * @param dictCode:
     * @return List<Dict>
     * @author Likejin
     * @description 根据dictCode编码查询其下级节点
     * @date 2023/4/15 20:00
     */

    List<Dict> findByDictCode(String dictCode);
}

com.atguigu.srb.core.service.impl.DictServiceImpl类下加入方法

    /**
     * @param dictCode:
     * @return List<Dict>
     * @author Likejin
     * @description 根据dictCode编码查询其下级节点
     * @date 2023/4/15 20:00
     */
    @Override
    public List<Dict> findByDictCode(String dictCode) {
        QueryWrapper<Dict> dictQueryWrapper = new QueryWrapper<>();
        dictQueryWrapper.eq("dict_code",dictCode);
        Dict dict = baseMapper.selectOne(dictQueryWrapper);
        //拿到父dict的id,然后根据该id去查父id等于这个id的list<Dict>
        return this.listByParentId(dict.getId());
    }

⑤借款人业务(获取认证状态)(保存借款人信息)

  • controller
package com.atguigu.srb.core.controller.api;

import com.atguigu.common.result.R;
import com.atguigu.srb.base.util.JwtUtils;
import com.atguigu.srb.core.pojo.vo.BorrowerVO;
import com.atguigu.srb.core.service.BorrowerService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

@Api(tags = "借款人")
@RestController
@RequestMapping("/api/core/borrower")
@Slf4j
public class BorrowerController {

    @Resource
    private BorrowerService borrowerService;

    @ApiOperation("保存借款人信息")
    @PostMapping("/auth/save")
    public R save(@RequestBody BorrowerVO borrowerVO, HttpServletRequest request) {
        //获取已经登录人的id
        String token = request.getHeader("token");
        Long userId = JwtUtils.getUserId(token);

        //存储表单信息
        borrowerService.saveBorrowerVOByUserId(borrowerVO, userId);
        return R.ok().message("信息提交成功");
    }

    @ApiOperation("获取借款人认证状态")
    @GetMapping("/auth/getBorrowerStatus")
    public R getBorrowerStatus(HttpServletRequest httpServletRequest){
        String token = httpServletRequest.getHeader("token");
        Long userId = JwtUtils.getUserId(token);
        Integer status = borrowerService.getStatusByUserId(userId);
        return R.ok().data("borrowerStatus",status);


    }
}
  • service
package com.atguigu.srb.core.service;

import com.atguigu.srb.core.pojo.entity.Borrower;
import com.atguigu.srb.core.pojo.vo.BorrowerVO;
import com.baomidou.mybatisplus.extension.service.IService;

/**
 * <p>
 * 借款人 服务类
 * </p>
 *
 * @author Likejin
 * @since 2023-04-09
 */
public interface BorrowerService extends IService<Borrower> {


    void saveBorrowerVOByUserId(BorrowerVO borrowerVO, Long userId);


    Integer getStatusByUserId(Long userId);
}

package com.atguigu.srb.core.service.impl;

import com.atguigu.srb.core.enums.BorrowerStatusEnum;
import com.atguigu.srb.core.mapper.BorrowerAttachMapper;
import com.atguigu.srb.core.mapper.UserInfoMapper;
import com.atguigu.srb.core.pojo.entity.Borrower;
import com.atguigu.srb.core.mapper.BorrowerMapper;
import com.atguigu.srb.core.pojo.entity.BorrowerAttach;
import com.atguigu.srb.core.pojo.entity.UserInfo;
import com.atguigu.srb.core.pojo.vo.BorrowerVO;
import com.atguigu.srb.core.service.BorrowerService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;

/**
 * <p>
 * 借款人 服务实现类
 * </p>
 *
 * @author Likejin
 * @since 2023-04-09
 */
@Service
public class BorrowerServiceImpl extends ServiceImpl<BorrowerMapper, Borrower> implements BorrowerService {


    @Resource
    private UserInfoMapper userInfoMapper;

    @Resource
    private BorrowerAttachMapper borrowerAttachMapper;
    /**
     * @param borrowerVO:
     * @param userId:
     * @return void
     * @author Likejin
     * @description 根据前端传输对象保存数据到数据库
     * @date 2023/4/15 20:15
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveBorrowerVOByUserId(BorrowerVO borrowerVO, Long userId) {


        //获取用户基本信息
        UserInfo userInfo = userInfoMapper.selectById(userId);
        //拷贝信息到borrower
        //保存借款人信息(根据id查询用户基本信息,然后根据表单信息更新borrower表)
        Borrower borrower = new Borrower();
        BeanUtils.copyProperties(borrowerVO,borrower);
        borrower.setUserId(userId);
        borrower.setName(userInfo.getName());
        borrower.setIdCard(userInfo.getIdCard());
        borrower.setMobile(userInfo.getMobile());
        borrower.setStatus(BorrowerStatusEnum.AUTH_RUN.getStatus());
        baseMapper.insert(borrower);

        //保存附件信息到borrow——attach表
        List<BorrowerAttach> borrowerAttachList = borrowerVO.getBorrowerAttachList();
        borrowerAttachList.forEach(borrowerAttach -> {
            borrowerAttach.setBorrowerId(borrower.getId());
            borrowerAttachMapper.insert(borrowerAttach);
        });

        //更新user_info的借款人认证状态
        userInfo.setBorrowAuthStatus(BorrowerStatusEnum.AUTH_RUN.getStatus());
        userInfoMapper.updateById(userInfo);

    }

    /**
     * @param userId:
     * @return Integer
     * @author Likejin
     * @description 借款人二次进入认证页面根据token获取认证状态
     * @date 2023/4/15 20:41
     */

    @Override
    public Integer getStatusByUserId(Long userId) {

        QueryWrapper<Borrower> borrowerQueryWrapper = new QueryWrapper<>();
        borrowerQueryWrapper.select("status").eq("user_id",userId);
        //selectObjs一般用于查询一个字段,list存的是status
        List<Object> objects = baseMapper.selectObjs(borrowerQueryWrapper);
        if(objects.size()==0){
            //一条记录没取出来,说明没有提交额度信息,需要填写表单
            return BorrowerStatusEnum.NO_AUTH.getStatus();
        }
        //取出来一条,说明已经提交了额度信息,判断此时状态
        Integer status = (Integer) objects.get(0);
        return status;
    }
}

未更新

未更新

未更新

未更新

未更新

未更新

未更新

未更新

未更新

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

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

相关文章

Linux从命令行管理文件

目录 一、创建链接文件 二、目录操作命令 1. 创建目录&#xff08;make directory&#xff09; 2. 统计目录及文件的空间占用情况 3. 删除目录文件 三、创建、删除普通文件 文件命名规则&#xff1a; &#xff08;1&#xff09;不能使用/来当文件名&#xff0c;/是用来做…

【WCH】CH32F203软件I2C驱动SSD1306 OLED

【WCH】CH32F203软件I2C驱动SSD1306 OLED&#x1f4cc;相关篇《【WCH】CH32F203硬件I2C驱动SSD1306 OLED》&#x1f4fa;驱动显示效果&#xff1a; &#x1f33f;OLED屏幕&#xff1a;i2c ssd1306 oled&#x1f516;驱动单片机型号&#xff1a;CH32F203 ✨由于CH32F203主频为96…

wordpress下载插件,安装失败,无法创建目录问题

刚开始安装这个wordpress&#xff0c;在发表文章时候想要在其中加上图片&#xff0c;不想一个个手动上传媒体库&#xff0c;耽误时间&#xff0c;然后就去下了个imagepaste这个复制粘贴的插件&#xff0c;当我打开安装插件搜索到的时候准备安装&#xff0c;尼玛出现“安装失败&…

若一个单词被拆分成多少token, word_ids得到的序号是相同的?还是序号累加的?

目录 问题描述&#xff1a; 问题实现&#xff1a; 方法一&#xff1a; 方法二&#xff1a; 问题描述&#xff1a; 在使用tokenizer进行编码的时候&#xff0c;经常会存在word被拆分成多个token的情况&#xff0c;不同的参数设置&#xff0c;会得到不同的结果。总的来说&…

redis——使用

session缓存缓存更新方式删除缓存vs更新缓存缓存和数据库操作原子性缓存和数据库操作顺序结论缓存问题缓存穿透缓存雪崩缓存击穿全局唯一ID数据并发线程安全单体分布式redis分布式锁的问题redis消息队列listpubsubstream消息推送session 问题&#xff1a;session存在tomcat服务…

【Linux驱动开发】023 platform设备驱动

一、前言 驱动分离目的&#xff1a;提高Linux代码重用性和可移植性。 二、驱动的分隔与分离 百度看了很多&#xff0c;大多都没讲清楚为什么使用platform驱动&#xff0c;为什么驱动分隔与分离可以提高代码重用性&#xff0c;只是在讲实现的结构体、函数接口等等&#xff0c…

npm、pnpm、yarn的常用命令

npm、pnpm、yarn的常用命令 文章目录npm、pnpm、yarn的常用命令一、常用命令1、npm命令2、pnpm命令&#xff1a;3、yarn命令二、对比一、常用命令 1、npm命令 npm init: 初始化一个新的npm包。 npm install: 安装项目依赖项。 npm install : 安装指定的包。 npm install --sa…

【Java数据结构】链表(Linked List)-双向链表

双向链表&#xff08;Linked List&#xff09;是一种常用的数据结构&#xff0c;它允许在所有节点中快速添加或删除元素&#xff0c;并且可以有效地实现反向遍历。本篇文章将介绍双向链表的基础知识&#xff0c;并提供使用Java语言实现该数据结构的示例代码。 一、双向链表的基…

mysql数据库事务脏读、不可重复度、幻读详解

文章目录1 事务隔离级别2 脏读3 不可重复度3.1 解决了脏读的问题。3.2 有不可重复度的问题4 幻读4.1 没有脏读和不可重复读的问题4.2 有幻读的问题5 serializable1 事务隔离级别 read-uncommitted&#xff1a;脏读、不可重复度、幻读&#xff0c;均可出现。安全性低&#xff0…

HBase架构篇 - Hadoop家族的天之骄子HBase

HBase的基本组成结构 表&#xff08;table&#xff09; HBase 的数据存储在表中。表名是一个字符串。表由行和列组成。 行&#xff08;row&#xff09; HBase 的行由行键&#xff08;rowkey&#xff09;和 n 个列&#xff08;column&#xff09;组成。行键没有数据类型&…

《花雕学AI》06:抢先体验ChatGPT的九个国内镜像站之试用与综合评测

最近ChatGPT持续大火&#xff0c;大家们是不是在网上看到各种和ChatGPT有趣聊天的截图&#xff0c;奈何自己实力不够&#xff0c;被网络拒之门外&#xff0c;只能眼馋别人的东西。看别人在体验&#xff0c;看别人玩&#xff0c;肯定不如自己玩一把舒服的啊。 上一期&#xff0…

2.5d风格的游戏模式如何制作

文章目录一、 介绍二、 绘制瓦片地图三、 添加场景物体&#xff0c;添加碰撞器四、 创建玩家五、 创建玩家动画六、 玩家脚本七、 2d转换成2.5d八、 “Q”键向左转动视角、“E”键向右转动视角九、 下载工程文件一、 介绍 制作一个类似饥荒风格的2.5d游戏模板。 2.5D游戏是指以…

Spring之循环依赖

什么事循环依赖 很简单的定义就是就如有两个对象A类&#xff0c;B类&#xff0c;其中两个类中的属性都有对方。 A类 public class A{private B b;}B类 public class B{ private A a; }在Spring中&#xff0c;什么情况下会出现循环依赖 如果要了解循环依赖&#xff0c;首先…

基于matlab进行雷达信号模拟

一、前言此示例说明如何将基本工具箱工作流应用于以下方案&#xff1a;假设有一个工作频率为 4 GHz 的各向同性天线。假设天线位于全局坐标系的原点。有一个目标&#xff0c;其非波动雷达横截面为0.5平方米&#xff0c;最初位于&#xff08;7000&#xff0c;5000&#xff0c;0&…

Linux下使用ClamAV病毒查杀

一、介绍Clam AntiVirus 是一款 UNIX 下开源的 (GPL) 反病毒工具包&#xff0c;专为邮件网关上的电子邮件扫描而设计。该工具包提供了包含灵活且可伸缩的监控程序、命令行扫描程序以及用于自动更新数据库的高级工具在内的大量实用程序。该工具包的核心在于可用于各类场合的反病…

CompletableFuture使用详解(IT枫斗者)

CompletableFuture使用详解 简介 概述 CompletableFuture是对Future的扩展和增强。CompletableFuture实现了Future接口&#xff0c;并在此基础上进行了丰富的扩展&#xff0c;完美弥补了Future的局限性&#xff0c;同时CompletableFuture实现了对任务编排的能力。借助这项能力…

2023最新快速单机创建三主三从Redis集群

单机搭建Redis集群 本次采用Redis的5.0.14版本在单机centos8上搭建Redis三主三从集群. 1.创建6个文件夹 一个文件夹代表一个节点,同时也代表每个节点的端口号. 2.下载Redis文件并解压 使用命令: #下载Redis 可以将5.0.14替换成自己想要的版本 wget http://download.redis…

JavaScript面向对象编程再讲

JavaScript面向对象编程再讲 JavaScript支持的面向对象比较复杂&#xff0c;和其他编程语言又有其独特之处。本文是对以前博文 JavaScript的面向对象编程 https://blog.csdn.net/cnds123/article/details/109763357 补充。 概述 这部分是JavaScript面向对象的概括&#xff0c…

计算机网络微课堂1-3节

目录 1. TCP/TP协议​编辑 2. 3.调制解调器 4.因特网的组成 5.电路交换 6.分组交换 重要常用 7.报文交换 8.总结电路交换 报文交换和分组交换 9. 1. TCP/TP协议 2. ISP 网络提供商 ISP的三层 国际 国家 和本地 3.调制解调器 什么是调制解调器&#xff0c;它存在的…

稳压二极管工作原理、重要参数意义和典型电路参数计算

稳压二极管的工作原理&#xff1a;稳压二极管也叫稳压管&#xff0c;它在电路中一般起到稳定电压的作用&#xff0c;也可以为电路提供基准电压值。稳压二极管使用特殊工艺制造&#xff0c;这种工艺使它在反向击穿时仍然可以长时间稳定工作&#xff0c;不损坏&#xff0c;而工作…