springboot + Vue前后端项目(第十四记)

news2024/11/25 13:18:01

项目实战第十三记

  • 写在前面
  • 1. 建立字典表
  • 2. 后端DictController
  • 3. Menu.vue
  • 4. 建立sys_role_menu中间表
  • 5.分配菜单接口
  • 6. 前端Role.vue改动
  • 总结
  • 写在最后

写在前面

本篇主要讲解动态分配菜单第二章节

  • 菜单页面优化
    引入图标在这里插入图片描述

  • 角色界面优化
    角色自主分配菜单,并保存至数据库
    在这里插入图片描述

1. 建立字典表


DROP TABLE IF EXISTS `sys_dict`;
CREATE TABLE `sys_dict`  (
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '名称',
  `value` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '内容',
  `type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '类型'
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = DYNAMIC;

-- ----------------------------
-- Records of sys_dict
-- ----------------------------
INSERT INTO `sys_dict` VALUES ('user', 'el-icon-user', 'icon');
INSERT INTO `sys_dict` VALUES ('user-solid', 'el-icon-user-solid', 'icon');
INSERT INTO `sys_dict` VALUES ('s-home', 'el-icon-s-home', 'icon');
INSERT INTO `sys_dict` VALUES ('menu', 'el-icon-menu', 'icon');
INSERT INTO `sys_dict` VALUES ('document', 'el-icon-document', 'icon');
INSERT INTO `sys_dict` VALUES ('map-location', 'el-icon-map-location', 'icon');

2. 后端DictController

package com.ppj.controller;


import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.Arrays;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ppj.common.Result;

import com.ppj.service.IDictService;
import com.ppj.entity.Dict;

import org.springframework.web.bind.annotation.RestController;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author ppj
 * @since 2024-05-30
 */
@RestController
@RequestMapping("/dict")
public class DictController {

    @Resource
    private IDictService dictService;

    // 新增或者更新
    @PostMapping
    public Result save(@RequestBody Dict dict) {
        dictService.saveOrUpdate(dict);
        return Result.success();
    }

    @DeleteMapping("/{dictIds}")
    public Result delete(@PathVariable Integer[] dictIds) {
        dictService.removeByIds(Arrays.asList(dictIds));
        return Result.success();
    }

    @GetMapping
    public Result findAll() {
        return Result.success(dictService.list());
    }

    @GetMapping("/page")
    public Result findPage(@RequestParam Integer pageNum,
                                @RequestParam Integer pageSize) {
        QueryWrapper<Dict> queryWrapper = new QueryWrapper<>();
        return Result.success(dictService.page(new Page<>(pageNum, pageSize), queryWrapper));
    }

}

3. Menu.vue

<template>
  <div>
    <!-- 设计的查询 -->
    <div style="margin: 10px 0">
      <el-input
          style="width: 200px"
          placeholder="请输入名称"
          suffix-icon="el-icon-search"
          v-model="name"
      />
      <el-button type="primary" icon="el-icon-search" class="ml-5" @click="getList"
      >搜索</el-button>
      <el-button type="warning" icon="el-icon-reset" @click="resetQuery"
      >重置</el-button>
    </div>

    <div style="margin: 10px 0">
      <el-button type="primary" @click="handleAdd">新增 <i class="el-icon-circle-plus-outline"></i></el-button>
      <el-button type="warning" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate">修改</el-button>
    </div>

    <el-table :data="tableData"
              row-key="id"
              @selection-change="handleSelectionChange">
      <el-table-column type="selection" width="55" />
      <el-table-column prop="id" label="菜单ID"></el-table-column>
      <el-table-column
          prop="name"
          label="菜单名称"
      ></el-table-column>
      <el-table-column
          prop="path"
          label="菜单路径"
      ></el-table-column>
      <el-table-column
          prop="icon"
          label="菜单图标"
      >
        <template v-slot="scope">
          <span :class="scope.row.icon" style="font-size: 20px;text-align: center"></span>
        </template>
      </el-table-column>
      <el-table-column prop="description" label="描述"></el-table-column>

      <el-table-column label="操作" width="300px">
        <template v-slot="scope">
          <el-button
              type="primary"
              @click="handleAdd(scope.row.id)"
              v-if="!scope.row.pid && !scope.row.path"
          >新增子菜单</el-button>
          <el-button type="success" @click="handleUpdate(scope.row)">编辑 <i class="el-icon-edit"></i></el-button>
          <el-button type="danger" @click="handleDelete(scope.row)">删除 <i class="el-icon-remove-outline"></i></el-button>
        </template>
      </el-table-column>
    </el-table>

    <!-- <div style="padding: 10px 0">
      <el-pagination
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
        :current-page="pageNum"
        :page-sizes="[5, 10, 15]"
        :page-size="pageSize"
        layout="total, sizes, prev, pager, next, jumper"
        :total="total"
      >
      </el-pagination>
    </div> -->

    <!-- 菜单添加对话框 -->
    <el-dialog title="菜单信息" :visible.sync="dialogFormVisible" width="30%">
      <el-form :model="form">
        <el-form-item label="菜单名称" :label-width="formLabelWidth">
          <el-input v-model="form.name" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="菜单路径" :label-width="formLabelWidth">
          <el-input v-model="form.path" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="图标" :label-width="formLabelWidth">
          <el-select clearable v-model="form.icon" placeholder="请选择" style="width: 100%">
            <el-option v-for="item in icons" :key="item.name" :label="item.name" :value="item.value">
              <i :class="item.value" /> {{ item.name }}
            </el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="描述" :label-width="formLabelWidth">
          <el-input v-model="form.description" autocomplete="off"></el-input>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="dialogFormVisible = false">取 消</el-button>
        <el-button type="primary" @click="save">确 定</el-button>
      </div>
    </el-dialog>

  </div>
</template>
<script>
export default {
  name: "Menu",
  data() {
    return {
      name: "",
      tableData: [],
      total: 0,
      pageSize: 5,
      pageNum: 1,
      dialogFormVisible: false,
      formLabelWidth: "80px",
      ids: [],
      // 非单个禁用
      single: true,
      // 非多个禁用
      multiple: true,
      form: {
        id: '',
        name: "",
        path: "",
        icon: "",
        description: "",
      },
      // 图标集合
      icons: []
    };
  },
  //页面一创建成功
  created() {
    //请求分页查询数据
    this.getList();
    this.getIcons();
  },
  methods: {
    getList() {
      this.request.get("/menu", {
            params: {
              name: this.name,
            },
          })
          .then((res) => {
            if(res.code === "200"){
              this.tableData = res.data;
            }else{
              this.$message.error(res.msg);
            }
          });
    },
    resetQuery() {
      this.name = "";
      this.pageNum = 1;
      this.pageSize = 5;
      this.getList();
    },
    handleSizeChange(val) {
      this.pageSize = val;
    },
    handleCurrentChange(val) {
      this.pageNum = val;
      this.getList();
    },
    // 多选框选中数据
    handleSelectionChange(selection) {
      this.ids = selection.map(item => item.id);
      this.single = selection.length != 1;
      this.multiple = !selection.length;
    },
    // 新增
    handleAdd(id){
      this.reset();
      this.dialogFormVisible = true;
      if(id){  // 新建子菜单时,设置父id
        this.form.pid = id;
      }
    },
    save(){
      this.request.post("/menu",this.form).then(res => {
        if(res.code === "200" || res.code === 200){
          this.$message.success("操作成功")
        }else {
          this.$message.error("操作失败")
        }
        this.dialogFormVisible = false;
        this.getList();
      })
    },
    // 修改
    handleUpdate(row){
      // 表单置空
      this.reset();
      // 重新查询数据
      const menuId = row.id || this.ids;
      this.request.get('/menu/'+menuId).then(response => {
        this.form = response.data;
        this.dialogFormVisible = true;
      });
    },
    reset(){
      this.form.path = undefined;
      this.form.name = undefined;
      this.form.icon = undefined;
      this.form.description = undefined;
    },
    // 删除
    handleDelete(row){
      let _this = this;
      const menuIds = row.id || this.ids;
      this.$confirm('是否确认删除菜单编号为"' + menuIds + '"的数据项?', '删除菜单', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        _this.request.delete("/menu/"+menuIds).then(res=>{
          if(res.code === "200" || res.code === 200){
            _this.$message.success("删除成功")
          }else {
            _this.$message.error("删除失败")
          }
          this.getList();
        })
      }).catch(() => {
      });
    },
    getIcons(){
      this.request.get("/dict").then(res => {
        if(res.code === "200"){
          this.icons = res.data
        }
      })
    }
  },
};
</script>

4. 建立sys_role_menu中间表


// 多对多   建立中间表,角色id和菜单id作为联合主键

CREATE TABLE `sys_role_menu` (
  `role_id` int(11) NOT NULL COMMENT '角色id',
  `menu_id` int(11) NOT NULL COMMENT '菜单id',
  PRIMARY KEY (`role_id`,`menu_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='角色菜单关系表'

5.分配菜单接口

RoleController

package com.ppj.controller;


import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ppj.service.IRoleMenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ppj.common.Result;

import com.ppj.service.IRoleService;
import com.ppj.entity.Role;

import org.springframework.web.bind.annotation.RestController;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author ppj
 * @since 2024-05-29
 */
@RestController
@RequestMapping("/role")
public class RoleController {

    @Resource
    private IRoleService roleService;

    @Autowired
    private IRoleMenuService roleMenuService;

    // 新增或者更新
    @PostMapping
    public Result save(@RequestBody Role role) {
        roleService.saveOrUpdate(role);
        return Result.success();
    }

    @DeleteMapping("/{roleIds}")
    public Result delete(@PathVariable Integer[] roleIds) {
        roleService.removeByIds(Arrays.asList(roleIds));
        return Result.success();
    }

    @GetMapping
    public Result findAll() {
        return Result.success(roleService.list());
    }

    @GetMapping("/{id}")
    public Result findOne(@PathVariable Integer id) {
        return Result.success(roleService.getById(id));
    }

    @GetMapping("/page")
    public Result findPage(@RequestParam Integer pageNum,
                           @RequestParam Integer pageSize,
                           @RequestParam(defaultValue = "") String name) {
        QueryWrapper<Role> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("name",name);
        return Result.success(roleService.page(new Page<>(pageNum, pageSize), queryWrapper));
    }

    @PostMapping("/roleMenu/{roleId}")
    public Result saveRoleMenu(@PathVariable("roleId") Integer roleId, @RequestBody Integer[] menuIds){
        roleMenuService.saveRoleMenu(roleId,menuIds);
        return Result.success();
    }

    @GetMapping("/roleMenu/{roleId}")
    public Result getRoleMenu(@PathVariable("roleId") Integer roleId){
        return Result.success(roleMenuService.getRoleMenu(roleId));
    }

}

RoleMenuServiceImpl

package com.ppj.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ppj.entity.RoleMenu;
import com.ppj.mapper.RoleMenuMapper;
import com.ppj.service.IRoleMenuService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.swagger.models.auth.In;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author ppj
 * @since 2024-05-31
 */
@Service
@Transactional
public class RoleMenuServiceImpl extends ServiceImpl<RoleMenuMapper, RoleMenu> implements IRoleMenuService {

    @Autowired
    private RoleMenuMapper roleMenuMapper;

    @Override
    public void saveRoleMenu(Integer roleId, Integer[] menuIds) {
        // 先删除该角色所有的权限
        QueryWrapper<RoleMenu> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("role_id",roleId);
        roleMenuMapper.delete(queryWrapper);
        // 在添加新的权限
        RoleMenu roleMenu = new RoleMenu();
        for (Integer menuId : menuIds) {
            roleMenu.setRoleId(roleId);
            roleMenu.setMenuId(menuId);
            save(roleMenu);
        }
    }

    @Override
    public List<Integer> getRoleMenu(Integer roleId) {
        QueryWrapper<RoleMenu> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("role_id",roleId);
        List<RoleMenu> roleMenus = roleMenuMapper.selectList(queryWrapper);
        List<Integer> menuIds = roleMenus.stream().map(RoleMenu::getMenuId).collect(Collectors.toList());
        return menuIds;
    }
}

6. 前端Role.vue改动

<template>
  <div>
    <!-- 设计的查询 -->
    <div style="margin: 10px 0">
      <el-input
          style="width: 200px"
          placeholder="请输入名称"
          suffix-icon="el-icon-search"
          v-model="name"
      />
      <el-button type="primary" icon="el-icon-search" class="ml-5" @click="getList"
      >搜索</el-button>
      <el-button type="warning" icon="el-icon-reset" @click="resetQuery"
      >重置</el-button>
    </div>

    <div style="margin: 10px 0">
      <el-button type="primary" @click="handleAdd">新增 <i class="el-icon-circle-plus-outline"></i></el-button>
      <el-button type="warning" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate">修改</el-button>
      <el-button type="danger" :disabled="multiple" @click="handleDelete">删除 <i class="el-icon-remove-outline"></i></el-button>
    </div>

    <el-table :data="tableData" @selection-change="handleSelectionChange">
      <el-table-column type="selection" width="55" />
      <el-table-column prop="id" label="角色ID" width="80"></el-table-column>
      <el-table-column prop="roleKey" label="唯一标识"></el-table-column>
      <el-table-column prop="name" label="角色名称"></el-table-column>
      <el-table-column prop="description" label="角色描述"></el-table-column>
      <el-table-column label="操作">
        <template v-slot="scope">
          <el-button
              type="info"
              icon="el-icon-menu"
              @click="openMenuAllocDialog(scope.row.id)"
          >分配菜单</el-button>
          <el-button type="success" @click="handleUpdate(scope.row)">编辑 <i class="el-icon-edit"></i></el-button>
          <el-button type="danger" @click="handleDelete(scope.row)">删除 <i class="el-icon-remove-outline"></i></el-button>
        </template>
      </el-table-column>
    </el-table>

    <div style="padding: 10px 0">
      <el-pagination
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
          :current-page="pageNum"
          :page-sizes="[5, 10, 15]"
          :page-size="pageSize"
          layout="total, sizes, prev, pager, next, jumper"
          :total="total"
      >
      </el-pagination>
    </div>

    <!-- 角色添加对话框 -->
    <el-dialog title="角色信息" :visible.sync="dialogFormVisible" width="30%">
      <el-form :model="form">
        <el-form-item label="唯一标识" :label-width="formLabelWidth">
          <el-input v-model="form.roleKey" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="角色名称" :label-width="formLabelWidth">
          <el-input v-model="form.name" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="描述" :label-width="formLabelWidth">
          <el-input v-model="form.description" autocomplete="off"></el-input>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="dialogFormVisible = false">取 消</el-button>
        <el-button type="primary" @click="save">确 定</el-button>
      </div>
    </el-dialog>

    <!-- 分配菜单 -->
    <el-dialog title="菜单分配" :visible.sync="menuDialogVis" width="30%">
      <el-tree
          :props="props"
          :data="menuData"
          show-checkbox
          node-key="id"
          ref="tree"
          :default-expanded-keys="expends"
          :default-checked-keys="checks">
         <span class="custom-tree-node" slot-scope="{ node, data }">
            <span><i :class="data.icon"></i> {{ data.name }}</span>
         </span>
      </el-tree>
      <div slot="footer" class="dialog-footer">
        <el-button @click="menuDialogVis = false">取 消</el-button>
        <el-button type="primary" @click="saveRoleMenu">确 定</el-button>
      </div>
    </el-dialog>

  </div>
</template>
<script>
export default {
  name: "Role",
  data() {
    return {
      name: "",
      tableData: [],
      total: 0,
      pageSize: 5,
      pageNum: 1,
      dialogFormVisible: false,
      menuDialogVis: false,
      formLabelWidth: "80px",
      ids: [],
      // 非单个禁用
      single: true,
      // 非多个禁用
      multiple: true,
      form: {
        id: "",
        name: "",
        description: "",
      },
      menuData: [],
      props: {
        label: 'name',
      },
      expends: [],
      checks: [],
      roleId: undefined,
    };
  },
  //页面一创建成功
  created() {
    //请求分页查询数据
    this.getList();
  },
  methods: {
    getList() {
      this.request
          .get("/role/page", {
            params: {
              pageNum: this.pageNum,
              pageSize: this.pageSize,
              name: this.name,
            },
          })
          .then((res) => {
            if(res.code === "200"){
              this.tableData = res.data.records;
              this.total = res.data.total;
            }else{
              this.$message.error(res.msg);
            }
          });
    },
    //分配菜单
    openMenuAllocDialog(id){
      this.menuDialogVis = true;
      // 角色id赋值
      this.roleId = id;
      //请求菜单数据
      this.request.get("/menu",{
        params: {
          name: ""
        }
      }).then(res => {
        this.menuData = res.data;
        //展开菜单数据
        this.expends = this.menuData.map(v => v.id);
      })
      // 展开已拥有的菜单
      this.request.get("/role/roleMenu/"+id).then(res => {
        this.checks = res.data;
      })
    },
    //保存角色下的菜单
    saveRoleMenu(){
      this.request.post("/role/roleMenu/"+ this.roleId, this.$refs.tree.getCheckedKeys()).then(res => {
        if(res.code === "200"){
          this.$message.success("保存成功");
          this.menuDialogVis = false;
        }else {
          this.$message.error("保存失败");
        }
      })
    },
    // 重置按钮
    resetQuery(){
      this.username = "";
      this.pageNum = 1;
      this.pageSize = 5;
      this.getList();
    },
    handleSizeChange(val) {
      this.pageSize = val;
    },
    handleCurrentChange(val) {
      this.pageNum = val;
      this.getList();
    },
    // 多选框选中数据
    handleSelectionChange(selection) {
      this.ids = selection.map(item => item.id);
      this.single = selection.length != 1;
      this.multiple = !selection.length;
    },
    // 新增
    handleAdd(){
      this.dialogFormVisible = true;
      this.form = {};
    },
    save(){
      this.request.post("/role",this.form).then(res => {
        if(res.code === "200" || res.code === 200){
          this.$message.success("操作成功")
        }else {
          this.$message.error("操作失败")
        }
        this.dialogFormVisible = false;
        this.getList();
      })
    },
    // 修改
    handleUpdate(row){
      // 表单置空
      this.reset();
      // 重新查询数据
      const roleId = row.id || this.ids;
      this.request.get('/role/'+roleId).then(response => {
        this.form = response.data;
        this.dialogFormVisible = true;
      });
    },
    reset(){
      this.form.roleKey = undefined;
      this.form.name = undefined;
      this.form.description = undefined;
    },
    // 删除
    handleDelete(row){
      let _this = this;
      const roleIds = row.id || this.ids;
      this.$confirm('是否确认删除角色编号为"' + roleIds + '"的数据项?', '删除角色', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        _this.request.delete("/role/"+roleIds).then(res=>{
          if(res.code === "200" || res.code === 200){
            _this.$message.success("删除成功")
          }else {
            _this.$message.error("删除失败")
          }
          this.getList();
        })
      }).catch(() => {
      });
    }
  },
};
</script>

总结

  • 本篇主要优化菜单页面和角色页面

写在最后

如果此文对您有所帮助,请帅戈靓女们务必不要吝啬你们的Zan,感谢!!不懂的可以在评论区评论,有空会及时回复。
文章会一直更新

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

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

相关文章

透明度技术在AI去衣中的双刃剑作用

引言&#xff1a; 在当今这个数字化时代&#xff0c;人工智能&#xff08;AI&#xff09;已经成为我们生活中不可或缺的一部分。它不仅改变了我们的工作方式&#xff0c;还影响了我们的娱乐和社交活动。然而&#xff0c;随着AI技术的不断发展&#xff0c;一些伦理问题也逐渐浮出…

Linux:subshell(子shell)和childprocess(子进程)

相关阅读 Linuxhttps://blog.csdn.net/weixin_45791458/category_12234591.html?spm1001.2014.3001.5482 一、预备知识 在进行这个话题之前&#xff0c;首先要了解Linux系统中一个进程是如何创建的&#xff0c;当一个命令被执行时&#xff0c;首先会在当前进程创建一个子进程…

SpringBoot发送Gmail邮件

1. 登录Gmail Gmail网址 点击右上角“小齿轮”&#xff0c;然后点击"查看所有设置" 点击“转发和 POP/IMAP”&#xff0c;按图中设置&#xff0c;然后点击保存&#xff1a; 2. 启用两步验证(https://myaccount.google.com/security) 登录上述网址&#xff0c;找…

msvcp100.dll丢失怎样修复?几种快速有效修复msvcp100.dll丢失的方法

在使用电脑时是不是遇到过关于msvcp100.dll丢失文件丢失的情况&#xff1f;出现这样的情况有什么办法可以将丢失的msvcp100.dll文件快速恢复&#xff1f;今天的这篇文章就将教大家几种能够有效的解决msvcp100.dll丢失问题的方法。 方法一&#xff1a;重启电脑 重启电脑是一种简…

jmeter多用户登录并退出教程

有时候为了模拟更真实的场景&#xff0c;在项目中需要多用户登录并退出操作&#xff0c;大致参考如下 多用户登录前面已经实现&#xff1a;参考博文 多用户登录并退出jmx文件&#xff1a;百度网盘 提取码&#xff1a;0000 一、多用户退出操作 添加一个setUp线程组&#xff0…

基恩士激光 速度 曝光等关系

一、基恩士 CtrlN 二、速度设置 计算扫描速度 曝光时间&#xff1a; 1:1 相机点间隔是0.025 &#xff0c;我们要扫描的图像也是1&#xff1a;1的话&#xff0c;速度可以为 采样周期我们设定为3K&#xff0c;假如我们的7000行就够了 速度V0.025&#xff08;线间隔&#xff0…

YOLOv10全网最新创新点改进系列:YOLOv10改进加入新型高效的多尺度注意力(EMA)模块保留每个通道的信息并减少计算成本!助力v10检测性能遥遥领先!

YOLOv10全网最新创新点改进系列&#xff1a;YOLOv10改进加入新型高效的多尺度注意力&#xff08;EMA&#xff09;模块保留每个通道的信息并减少计算成本&#xff01;助力v10检测性能遥遥领先&#xff01; 所有改进代码均经过实验测试跑通&#xff01; 此项目不低于30种改进&am…

hadoop(1)--hdfs部署(亲测可用)

一、准备&#xff1a; 1、三台集群部署&#xff0c;配置hosts #cat /etc/hosts 192.168.46.128 node1 #nameNode dataNode secondaryNameNode 192.168.46.129 node2 #datanode 192.168.46.130 node3 #datanode说明&#xff1a; NameNode: 主节点管理者 DataNode&…

解决el-dialog里嵌入el-tabs卡死的问题

文章目录 1. 解决 el-dialog 里嵌入 el-tabs 卡死的问题 1. 解决 el-dialog 里嵌入 el-tabs 卡死的问题 今天发现在element ui里面使用 el-dialog 会导致页面卡死&#xff0c;本来我心想这么简单的一个弹窗&#xff0c;怎么会卡死解决思路&#xff1a;以为是项目的问题&#x…

展台搭建时打造完美的展示空间

1、确定主题和目标 在展台设计搭建之前&#xff0c;需要明确展示的主题和目标&#xff0c;包括展示内容、目标观众、品牌形象等。这有助于为展台设计搭建提供明确的方向和指导。 2、精细化设计 展台设计需要精细化&#xff0c;注重每一个细节的把控。包括展台结构、色彩搭配、材…

4. MySQL 约束

文章目录 【 1. 主键约束 PRIMARY KEY 】1.1 在创建表时设置主键约束设置单字段主键在创建表时设置联合主键 1.2 在修改表时添加主键约束1.3 删除主键约束1.4 主键自增长 AUTO_INCREMENT指定自增字段初始值自增字段不连续 【 2. 外键约束 FOREIGN KEY 】2.1 在创建表时设置外键…

探索无限可能:API平台引领数据驱动的新时代

在数字化浪潮的推动下&#xff0c;数据已成为推动商业创新和增长的核心动力。然而&#xff0c;数据的获取、整合和应用并非易事&#xff0c;需要跨越技术、安全和效率等多重挑战。幸运的是&#xff0c;API&#xff08;应用程序接口&#xff09;平台的出现&#xff0c;为我们打开…

使用 Django Model 构建强大的数据库模型

文章目录 创建一个简单的 Django Model迁移数据库使用 Django Shell 操作模型Django Admin结论 在 Django 中&#xff0c;Model 是构建数据库模型的基础。它允许开发人员定义数据的结构&#xff0c;并提供了方便的方式来与数据库进行交互。本文将介绍如何使用 Django Model 来创…

LangChain之Agent代理(上)

LangChain之Agent代理 Agent代理概述分类 Agent的基本使用准备操作定义工具1.Tavily在线搜索2.创建检索器3.得到工具列表 初始化大模型创建Agent运行Agent添加记忆 Agent代理 概述 Agent代理的核心思想是使用语言模型来选择要采取的一系列动作。在链中&#xff0c;动作序列是硬…

IP地址在字符串形式、数字形式和byte数组中的转换

IP地址 ip地址,我们以ipv4为例,字符串形式为:“192.168.0.1”,可以转换成dword类型的数据: on key a {char ipv4AddrStr[16] = "192.168.0.1";//16进制:c0.a8.0.1dword ipv4AddrNum;ipv4AddrNum = ipGetAddressAsNumber(ipv4AddrStr);write("ipv4AddrNu…

Linus Torvalds把控着linux内核开发审核,他去世之后linux内核会怎样?

在开始前刚好我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「linux的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01; Linus Torvalds 是 Linux…

【算法】模拟算法——替换所有的问号(easy)

题解&#xff1a;替换所有的问好(模拟算法) 目录 1.题目2.题解3.参考代码4.总结 1.题目 题目链接&#xff1a;LINK 2.题解 纯模拟。从前往后遍历整个字符串&#xff0c;找到问号之后&#xff0c;就⽤ a ~ z 的每⼀个字符去尝试替换即可。 3.参考代码 class Solution { pu…

下载安装nvm,使用nvm管理node.js版本

目录 一、下载安装nvm&#xff08;windows&#xff09; 二、使用nvm管理node.js版本 &#xff08;1&#xff09;nvm命令行 &#xff08;2&#xff09; 使用nvm管理node.js版本 ①查看nvm版本 ②显示活动的node.js版本 ③列出可供下载的node.js版本 ④安装node.js指定版本 ⑤列出…

36个JavaScript特效教程,学完即精通

课程目录 &#x1f9d1;‍&#x1f4bb;36个JavaScript特效教程&#xff0c;学完即精通 &#x1f381;【更多好课】资源仓库&#xff0c;海量资源&#xff0c;无偿分享√ 本站所有素材均来自于互联网&#xff0c;版权属原著所有&#xff0c;如有需要请购买正版。如有侵权&…

【测试】linux快捷指令工具cxtool

简介 登录linux时,我们经常需要重复输入一些指令. 这个工具可以把这些指令预置,需要的时候鼠标一点,会自动按预置的字符敲击键盘,敲击出指令. 下载地址 https://download.csdn.net/download/bandaoyu/89379371 使用方法 1,编辑配置文件&#xff0c;自定义自己的快捷指令。 2…