权限管理---尚硅谷

news2024/11/26 4:39:06

1.项目基础
2.定义统一返回结果对象
3.Nodejs
4.前端内容编写
5.菜单详情
6.SpringSecurity权限管理
7.添加登录日志
8.操作日志
9.后端打包
10.前端打包
11.动态sql日期的判断

项目基础

在这里插入图片描述

定义统一返回结果对象

  1. 定义全局统一返回结果类
import lombok.Data;

/**
 * 全局统一返回结果类
 *
 */
@Data
public class Result<T> {

    //返回码
    private Integer code;

    //返回消息
    private String message;

    //返回数据
    private T data;

    public Result(){}

    // 返回数据
    protected static <T> Result<T> build(T data) {
        Result<T> result = new Result<T>();
        if (data != null)
            result.setData(data);
        return result;
    }

    public static <T> Result<T> build(T body, Integer code, String message) {
        Result<T> result = build(body);
        result.setCode(code);
        result.setMessage(message);
        return result;
    }

    public static <T> Result<T> build(T body, ResultCodeEnum resultCodeEnum) {
        Result<T> result = build(body);
        result.setCode(resultCodeEnum.getCode());
        result.setMessage(resultCodeEnum.getMessage());
        return result;
    }

    public static<T> Result<T> ok(){
        return Result.ok(null);
    }

    /**
     * 操作成功
     * @param data  baseCategory1List
     * @param <T>
     * @return
     */
    public static<T> Result<T> ok(T data){
        Result<T> result = build(data);
        return build(data, ResultCodeEnum.SUCCESS);
    }

    public static<T> Result<T> fail(){
        return Result.fail(null);
    }

    /**
     * 操作失败
     * @param data
     * @param <T>
     * @return
     */
    public static<T> Result<T> fail(T data){
        Result<T> result = build(data);
        return build(data, ResultCodeEnum.FAIL);
    }

    public Result<T> message(String msg){
        this.setMessage(msg);
        return this;
    }

    public Result<T> code(Integer code){
        this.setCode(code);
        return this;
    }
}
  1. 定义统一返回结果状态信息类
import lombok.Getter;

/**
 * 统一返回结果状态信息类
 *
 */
@Getter
public enum ResultCodeEnum {

    SUCCESS(200,"成功"),
    FAIL(201, "失败"),
    SERVICE_ERROR(2012, "服务异常"),
    DATA_ERROR(204, "数据异常"),
    ILLEGAL_REQUEST(205, "非法请求"),
    REPEAT_SUBMIT(206, "重复提交"),
    ARGUMENT_VALID_ERROR(210, "参数校验异常"),

    LOGIN_AUTH(208, "未登陆"),
    PERMISSION(209, "没有权限"),
    ACCOUNT_ERROR(214, "账号不正确"),
    PASSWORD_ERROR(215, "密码不正确"),
    LOGIN_MOBLE_ERROR( 216, "账号不正确"),
    ACCOUNT_STOP( 217, "账号已停用"),
    NODE_ERROR( 218, "该节点下有子节点,不可以删除")
    ;

    private Integer code;

    private String message;

    private ResultCodeEnum(Integer code, String message) {
        this.code = code;
        this.message = message;
    }
}
  1. 编写controller,返回对象

在这里插入图片描述

Node.js

在这里插入图片描述

NPM 构建前端项目-管理依赖

在这里插入图片描述

模块化开发

  1. 设置方法,设置那些方法可以被其他js调用
    在这里插入图片描述

  2. 引入js文件,调用其方法
    在这里插入图片描述

ES6写法

  1. 定义方法,加上export关键字
    在这里插入图片描述
  2. import 的方式 只取需要的方法即可,多个方法用逗号分隔
    在这里插入图片描述
  3. 需要进行转码 将自己转为es5 babel 文件 -d 转后的文件名称
    在这里插入图片描述

es6 的第二种写法

  1. 定义方法

在这里插入图片描述2. 调用方法
在这里插入图片描述
3. 进行转码操作,运行操作
babel es6-2 -d es5-2
babel-node --presets env 2.js在这里插入图片描述
npm run dev

vue修改访问本地端口

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

角色列表的实现

  1. 添加角色管理路由
    在这里插入图片描述

角色开发 创建路由 创建页面

在这里插入图片描述

在这里插入图片描述

2.Api定义接口

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

3.调用api方法,获取响应的数据

在这里插入图片描述
在这里插入图片描述

4.把接口返回的数据进行处理

查询

在这里插入图片描述
列表
在这里插入图片描述

3. 分页

在这里插入图片描述

4. 列表删除

在这里插入图片描述

新增方法

在这里插入图片描述

修改方法

在这里插入图片描述

批量删除

在这里插入图片描述

<template>
  <div class="app-container">
    角色列表
    <!--查询表单-->
    <div class="search-div">
      <el-form label-width="70px" size="small">
        <el-row>
          <el-col :span="24">
            <el-form-item label="角色名称">
              <el-input style="width: 100%" v-model="searchObj.roleName" placeholder="角色名称"></el-input>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row style="display:flex">
          <el-button type="primary" icon="el-icon-search" size="mini"  @click="fetchData()">搜索</el-button>
          <el-button icon="el-icon-refresh" size="mini" @click="resetData">重置</el-button>
        </el-row>
      </el-form>
    </div>
    <!-- 工具条 -->
  <div class="tools-div">
    <el-button type="success" icon="el-icon-plus" size="mini" @click="add">添 加</el-button>
    <el-button class="btn-add" size="mini" @click="batchRemove()" >批量删除</el-button>
  </div>
    <!-- 表格  listLoading 页面加载转圈效果   :data="list" -- list 每页的列表数据    -->
    <el-table
      v-loading="listLoading"
      :data="list"           
      stripe
      border
      style="width: 100%;margin-top: 10px;"


      @selection-change="handleSelectionChange">// 改变复选框就会触发条件 

      <el-table-column type="selection"/>  // table 组件上添加复选框
      

      <el-table-column
        label="序号"
        width="70"
        align="center">
        <template slot-scope="scope">
          {{ (page - 1) * limit + scope.$index + 1 }}
        </template>
      </el-table-column>

      <el-table-column prop="roleName" label="角色名称" />
      <el-table-column prop="roleCode" label="角色编码" />
      <el-table-column prop="createTime" label="创建时间" width="160"/>
      <el-table-column label="操作" width="200" align="center">
        <template slot-scope="scope">
          <el-button type="primary" icon="el-icon-edit" size="mini" @click="edit(scope.row.id)" title="修改"/>
          <el-button type="danger" icon="el-icon-delete" size="mini" @click="removeDataById(scope.row.id)" title="删除"/>
          <el-button type="warning" icon="el-icon-baseball" size="mini" @click="showAssignAuth(scope.row)" title="分配权限"/>
        </template>
      </el-table-column>
    </el-table>

  <!-- 分页组件 -->
    <el-pagination
      :current-page="page"
      :total="total"
      :page-size="limit"
      style="padding: 30px 0; text-align: center;"
      layout="total, prev, pager, next, jumper"
      @current-change="fetchData"
    />

    <el-dialog title="添加/修改" :visible.sync="dialogVisible" width="40%" >
          <el-form ref="dataForm" :model="sysRole" label-width="150px" size="small" style="padding-right: 40px;">
            <el-form-item label="角色名称">
              <el-input v-model="sysRole.roleName"/>
            </el-form-item>
            <el-form-item label="角色编码">
              <el-input v-model="sysRole.roleCode"/>
            </el-form-item>
          </el-form>
          <span slot="footer" class="dialog-footer">
            <el-button @click="dialogVisible = false" size="small" icon="el-icon-refresh-right">取 消</el-button>
            <el-button type="primary" icon="el-icon-check" @click="saveOrUpdate()" size="small">确 定</el-button>
          </span>
    </el-dialog>
  </div>
</template>
<script>
//引入定义接口的js文件
import api from '@/api/system/role'

export default {
  //定义初始值/初始变量
  data() {
    return {
      listLoading:false,//是否显示加载
      list:[],//角色列表
      total:0,//总记录数
      page:1,//当前页
      limit:3,//每页显示记录数
      
      searchObj:{},//条件查询封装对象

      dialogVisible: false,//弹出框
      sysRole:{}, //封装添加表单数据
      selectValue:[] //复选框选择内容封装数组
    }
  },
  //页面渲染之前执行
  created() {
    //调用列表方法
    this.fetchData()
  },
  methods:{//具体方法
    //跳转分配菜单权限
    showAssignAuth(row) {
      this.$router.push('/system/assignAuth?id='+row.id+'&roleName='+row.roleName);
    },
    //复选框发生变化执行方法
    handleSelectionChange(selection) {
      this.selectValue = selection
      //console.log(this.selectValue)
    },
    //批量删除
    batchRemove() {
      //判断
      if(this.selectValue.length==0) {
        this.$message.warning('请选择要删除的记录!')
        return
      }
      this.$confirm('此操作将永久删除该角色, 是否继续?', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {
          //数组
          var idList = []
          //获取多个复选框对应id,封装到数组里面
          // [1,2,3]
          for(var i=0;i<this.selectValue.length;i++) {
            var obj = this.selectValue[i]
            //id值
            var id = obj.id
            //放到数组里面
            idList.push(id)
          }
          api.batchRemove(idList).then(response => {
              //提示
              this.$message({
                type: 'success',
                message: '删除成功!'
              });
              //刷新
              this.fetchData()
          })
        })
    },
    //修改-数据回显
    edit(id) {
      //弹出框
      this.dialogVisible = true
      api.getRoleId(id).then(response => {
        this.sysRole = response.data
      })
    },
    //点击确定
    saveOrUpdate() {
      //判断添加还是修改
      if(!this.sysRole.id) {
        //添加
        this.saveRole()
      } else {
        this.updateRole()
      }
    },
    //修改的方法
    updateRole() {
      api.update(this.sysRole)
        .then(response => {
          //提示
          this.$message({
            type: 'success',
            message: '修改成功!'
          });
          //关闭弹框
          this.dialogVisible = false
          //刷新页面
          this.fetchData()
        })
    },
    //添加的方法
    saveRole() {
      api.saveRole(this.sysRole)
        .then(response => {
          //提示
          this.$message({
            type: 'success',
            message: '添加成功!'
          });
          //关闭弹框
          this.dialogVisible = false
          //刷新页面
          this.fetchData()
        })
    },
    //点击添加,弹出框
    add() {
      this.dialogVisible = true
      this.sysRole = {}
    },
    //删除
    removeDataById(id) {
       this.$confirm('此操作将永久删除该角色, 是否继续?', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {
          //调用方法删除
          api.removeId(id)
            .then(response => {
              //提示
              this.$message({
                type: 'success',
                message: '删除成功!'
              });
              //刷新
              this.fetchData()
          })
        })
    },
    //重置
    resetData() {
      //清空表单
      this.searchObj = {}
      //查询所有数据
      this.fetchData()
    },
    //条件分页查询列表
    //pageNum 查询页数
    fetchData(pageNum=1) {
      //页数赋值
      this.page = pageNum
      //ajax
      api.getPageList(this.page,this.limit,this.searchObj)
        .then(response => {      // 调用接口成功执行then方法
          //this.listLoading = false
          //console.log(response)
          //每页数据列表
          this.list = response.data.records
          //总记录数
          this.total = response.data.total
        })
    }
  }
}
</script>


api

import request from '@/utils/request'

//常量
const api_name = '/admin/system/sysUser'

export default {
    //列表
    getPageList(page,limit,searchObj) {
        return request({
            //接口路径
            url: `${api_name}/${page}/${limit}`,
            method: 'get', //提交方式
            //参数
            params: searchObj
        })
    },
    //添加
    save(user) {
        return request({
            //接口路径
            url: `${api_name}/save`,
            method: 'post', //提交方式
            //参数
            data: user
        })
    },
    //根据id查询
    getUserId(id) {
        return request({
            //接口路径
            url: `${api_name}/getUser/${id}`,
            method: 'get' //提交方式
        })
    },
    //修改
    update(user) {
        return request({
            //接口路径
            url: `${api_name}/update`,
            method: 'post', //提交方式
            //参数
            data: user  // 将结果转为list进行传递
        })
    },
    //删除
    removeById(id) {
        return request({
            //接口路径
            url: `${api_name}/remove/${id}`,
            method: 'delete' //提交方式
        })
    },
    //更改用户状态
    updateStatus(id,status) {
        return request({
            //接口路径
            url: `${api_name}/updateStatus/${id}/${status}`,
            method: 'get' //提交方式
        })
    },
}

禁用启用

在这里插入图片描述

 //更改用户状态
    switchStatus(row) {
      //判断,如果当前用户可用,修改禁用
      row.status = row.status === 1 ? 0 : 1
      api.updateStatus(row.id,row.status)
        .then(response => {
          this.$message.success(response.message || '操作成功')
          this.fetchData()
        })
    },


 <el-table-column prop="username" label="用户名" width="180"/>
      <el-table-column prop="name" label="姓名" width="110"/>
      <el-table-column prop="phone" label="手机" />
      <el-table-column label="状态" width="80">
        <template slot-scope="scope">
          <el-switch
            v-model="scope.row.status===1"
            @change="switchStatus(scope.row)">
          </el-switch>
        </template>
      </el-table-column>


 //更改用户状态
    updateStatus(id,status) {
        return request({
            //接口路径
            url: `${api_name}/updateStatus/${id}/${status}`,
            method: 'get' //提交方式
        })
    },

菜单管理

在这里插入图片描述
在这里插入图片描述

代码实现

当前节点下存在子节点使用递归的方式
在这里插入图片描述

在这里插入图片描述

import com.qwq.model.system.SysMenu;

import java.util.ArrayList;
import java.util.List;

public class MenuHelper {

    // 构建树形结构
    public static List<SysMenu> bulidTree(List<SysMenu> list) {
        List<SysMenu> trees = new ArrayList<>();
        for (SysMenu sysMenu : list) {
             //先得到根节点进行遍历
            if (sysMenu.getParentId().longValue() == 0) {
                trees.add(findChildren(sysMenu,list));
            }
        }
        return trees;
    }


    /**
     * 递归查找子节点
     * @param treeNodes
     * @return
     */
    public static SysMenu findChildren(SysMenu sysMenu, List<SysMenu> treeNodes) {
        sysMenu.setChildren(new ArrayList<SysMenu>());

        // sysMenu = 根节点    treeNodes = 全部数据集合

        //  遍历全部数据
        for (SysMenu it : treeNodes) {
            String id = sysMenu.getId();
            long ids = Long.parseLong(id);
            // 全部数据的ParentId
            Long parentId = it.getParentId();

            //  根节点 id == 遍历数据的parentId
            //  2 == 3  3 == 6
            if (ids == parentId) {
                System.out.println(ids +"============"+ it.getId());
                sysMenu.getChildren().add(findChildren(it ,  treeNodes));
            }
        }
        return sysMenu;
    }
}

权限管理

关于安全方面的两个核心功能是“认证”和“授权”,一般来说,Web 应用的安全性包括**用户认证(Authentication)和用户授权(Authorization)**两个部分,这两点也是 SpringSecurity 重要核心功能。

(1)用户认证指的是:验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统。用户认证一般要求用户提供用户名和密码,系统通过校验用户名和密码来完成认证过程。

通俗点说就是系统认为用户是否能登录

(2)用户授权指的是验证某个用户是否有权限执行某个操作。在一个系统中,不同用户所具有的权限是不同的。比如对一个文件来说,有的用户只能进行读取,而有的用户可以进行修改。一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限。

通俗点讲就是系统判断用户是否有权限去做某些事情。

用户认证流程

在这里插入图片描述

添加登录日志

验证登录的拦截器登录成功后,调用service , request转化为ip , 进行新增处理
在这里插入图片描述

public class IpUtil {

    public static String getIpAddress(HttpServletRequest request) {
        String ipAddress = null;
        try {
            ipAddress = request.getHeader("x-forwarded-for");
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getHeader("Proxy-Client-IP");
            }
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getHeader("WL-Proxy-Client-IP");
            }
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getRemoteAddr();
                if (ipAddress.equals("127.0.0.1")) {
                    // 根据网卡取本机配置的IP
                    InetAddress inet = null;
                    try {
                        inet = InetAddress.getLocalHost();
                    } catch (UnknownHostException e) {
                        e.printStackTrace();
                    }
                    ipAddress = inet.getHostAddress();
                }
            }
            // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
            if (ipAddress != null && ipAddress.length() > 15) { // "***.***.***.***".length()
                // = 15
                if (ipAddress.indexOf(",") > 0) {
                    ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
                }
            }
        } catch (Exception e) {
            ipAddress="";
        }
        // ipAddress = this.getRequest().getRemoteAddr();

        return ipAddress;
    }

    public static String getGatwayIpAddress(ServerHttpRequest request) {
        HttpHeaders headers = request.getHeaders();
        String ip = headers.getFirst("x-forwarded-for");
        if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
            // 多次反向代理后会有多个ip值,第一个ip才是真实ip
            if (ip.indexOf(",") != -1) {
                ip = ip.split(",")[0];
            }
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = headers.getFirst("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = headers.getFirst("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = headers.getFirst("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = headers.getFirst("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = headers.getFirst("X-Real-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddress().getAddress().getHostAddress();
        }
        return ip;
    }
}

操作日志

在这里插入图片描述

后端打包

pom文件新增build标签


    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

在这里插入图片描述

<div id = ‘10’ / > 前端打包

在这里插入图片描述
输入命令进行打包
在这里插入图片描述
在这里插入图片描述

日期

格式:

<!--mapper的全限定类名-->
<mapper namespace="com.qwq.system.mapper.SysMenuMapper">


    <resultMap id="sysMenuMap" type="com.qwq.model.system.SysMenu" autoMapping="true">
    </resultMap>

    <!-- 用于select查询公用抽取的列 -->
    <sql id="columns">
      m.id,m.parent_id,m.name,m.type,m.path,m.component,m.perms,m.icon,m.sort_value,m.status,m.create_time,m.update_time,m.is_deleted
   </sql>


    <select id="findListByUserId" resultMap="sysMenuMap">
        select
        distinct <include refid="columns" />
        from sys_menu m
        inner join sys_role_menu rm on rm.menu_id = m.id
        inner join sys_user_role ur on ur.role_id = rm.role_id
        where
        ur.user_id = #{userId}
        and m.status = 1
        and rm.is_deleted = 0
        and ur.is_deleted = 0
        and  m.is_deleted = 0
    </select>

</mapper>

在这里插入图片描述

mybatis-plus的操作

在这里插入图片描述

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

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

相关文章

小程序容器技术助力突破智能汽车瓶颈

作为一种综合系统&#xff0c;智能车辆集环境感知、规划决策、多等级辅助驾驶等功能于一体。近年来&#xff0c;智能车辆已经成为世界车辆工程领域研究的热点和汽车工业增长的新动力&#xff0c;很多发达国家都将其纳入到各自重点发展的智能交通系统当中。在共享经济兴起和汽车…

如何写好JS

本节课从实践维度解读在实际编码过程中何种类型的 JavaScript 代码称之为“好代码”&#xff0c;并从 JS 出发&#xff0c;总结其他语言编码可遵循的共性原则&#xff0c;由浅入深&#xff0c;其三大原则是&#xff1a; 各司其职——html&#xff0c;css&#xff0c;js分离组件…

通达信接口QQ是什么端口?

可以将通达信接口QQ视为使用通达信市场软件作为数据库&#xff0c;然后将信息整合为策略的前提&#xff0c;所有行为都是自动化的。通达信接口的优势在于交易策略是事先制定的。是否基于市场波动&#xff0c;不受个人情绪的影响&#xff0c;可以大大降低个人原因造成的错误。 …

[ACTF2020 新生赛]BackupFile

目录 信息收集 思路 构造payload 知识补充 信息收集 从题目来看应该是让扫描备份文件(backupfile) 进入页面就一句话 Try to find out source file! 先用dirbuster模糊扫描一下目录 常见的如下 index.phps index.php.swp index.php.swo index.php.php~ index.php.bak ind…

有哪些数据恢复软件?13个好用的数据恢复工具分享

个人编辑开发了此资源&#xff0c;以帮助购买者寻找最好的免费数据恢复软件来满足其组织的需求。选择合适的供应商和工具可能是一个复杂的过程&#xff0c;需要深入研究&#xff0c;而且往往不仅仅取决于工具及其技术能力。为了让您的搜索更轻松一些&#xff0c;我们在一个地方…

【C++】stack和queue的使用

文章目录Stackstack容器的定义方式:接口函数queuequeue容器的定义方式接口函数栈OJ题目最小栈栈的压入,弹出序列逆波兰表达式求值(后缀表达式)中缀表达式->后缀表达式用两个栈实现队列队列OJ题用队列实现栈使用两个队列实现栈使用一个队列实现栈二叉树的层序遍历I二叉树的层…

k8s之挂载本地磁盘到POD中

写在前面 本文一起看下如何挂载本地的磁盘到POD中。 1&#xff1a;都需要哪些API对象 现实世界中的存储设备有非常非常多的种类&#xff0c;如本文要分析的计算机磁盘&#xff0c;还包括NFS(一种网络磁盘存储协议)&#xff0c;Ceph&#xff08;一种分布式的文件存储系统&…

Web测试的各个测试点

1.什么是Web测试&#xff1f; Web测试测试Web或Web应用程序的潜在错误。它是在上线前对基于网络的应用程序进行完整的测试。 UI测试 功能测试 数据库测试 性能测试 兼容性测试 安全测试 自动化测试 2.WEB测试主要测试场景 1.UI测试 界面是否美观&#xff0c;风格、字体、…

【青训营】Go的并发编程

本文章整理自——字节跳动青年训练营&#xff08;第五届&#xff09;后端组 1.线程和协程 操作系统中有三个重要的概念&#xff0c;分别是进程、线程和协程。其中进程和线程的区别请移步操作系统专栏&#xff0c;现在主要叙述线程和协程的区别。 简单来说&#xff0c;协程又称…

看我们网络故障分析系统如何发现系统500报错

背景 汽车配件电子图册系统是某汽车集团的重要业务系统。业务部门反映&#xff0c;汽车配件电子图册调用图纸时&#xff0c;出现访问慢现象。 汽车集团总部已部署NetInside流量分析系统&#xff0c;使用流量分析系统提供实时和历史原始流量。本次分析重点针对汽车配件电子图册…

Python学习笔记-网络爬虫基础

一、网络爬虫概述网络爬虫概述网络爬虫又称网络蜘蛛、网络机器人&#xff0c;在某社区中经常被称为网页追逐者。网络爬虫可以按照指定规则自动浏览或抓取网络中的信息&#xff0c;python可以很轻松的编写爬虫程序或脚本。网络爬虫基本工作流程&#xff1a;网络爬虫的常用技术2.…

【QT5 实现“上图下文”,带图标的按键样式-toolbutton-学习笔记-记录-基础样例】实现方式之一

【QT5 实现“上图下文”&#xff0c;带图标的按键样式-toolbutton-学习笔记-记录-基础样例】1、前言2、实验环境3、效果展示4、实验步骤第一步&#xff1a;新建工程-并运行。第二步&#xff1a;上网找图标文件第四步&#xff1a;&#xff08;非必须&#xff09;为了对比图标不同…

23种设计模式(三)——观察者模式【组件协作】

文章目录意图什么时候使用观察者使用观察者模式也有两个重点问题要解决&#xff1a;1&#xff09;广播链的问题2&#xff09;异步处理问题真实世界类比观察者模式的实现观察者模式的优缺点亦称&#xff1a;事件订阅者、监听者、Event-Subscriber、Listener、Observer 意图 在许…

mybatis之动态SQL测试环境的搭建以及if语句的使用

动态SQL&#xff1a; 动态 SQL 是 MyBatis 的强大特性之一&#xff0c;如果你使用过 JDBC 或其它类似的框架&#xff0c;你应该能理解根据不同条件拼接 SQL 语句有多痛苦&#xff0c;例如拼接时要确保不能忘记添加必要的空格&#xff0c;还要注意去掉列表最后一个列名的逗号&a…

Vue CLI

介绍 Vue CLI 是一个基于 Vue.js 进行快速开发的完整系统&#xff0c;提供&#xff1a; 通过 vue/cli 实现的交互式的项目脚手架。 通过 vue/cli vue/cli-service-global实现的零配置原型开发。 一个运行时依赖 (vue/cli-service)&#xff0c;该依赖&#xff1a; 可升级&a…

腾讯安全发布《2022年DDoS攻击威胁报告》:DDoS威胁4年持续增长

随着全球数字化蓬勃发展&#xff0c;互联网的应用范围不断扩大&#xff0c;并逐渐普及到各行各业的生产、管理、运营等方面&#xff0c;网络设备可用带宽伴随应用需求的增加而增加&#xff0c;方便了企业业务开展的同时也扩大了安全威胁面&#xff0c;引来黑产的觊觎。DDoS攻击…

Java使用流去除集合中某个字段为空的对象

文章目录0 写在前面1 情景复刻2 解决方案3 写在最后0 写在前面 最近写了一些业务逻辑&#xff0c;调试的时候总会报空指针异常。 Java中空指针异常是危险恐怖分子&#xff0c;最好不要碰见他。所以有些时候&#xff0c;处理集合中的数据时&#xff0c;特定情况下需要略过一些数…

十五天学会Autodesk Inventor,看完这一系列就够了(二),软件界面

众所周知&#xff0c;Autocad是一款用于二维绘图、详细绘制、设计文档和基本三维设计&#xff0c;现已经成为国际上广为流行的绘图工具。Autodesk Inventor软件也是美国AutoDesk公司推出的三维可视化实体模拟软件。因为很多人都熟悉Autocad&#xff0c;所以再学习Inventor&…

RK3568工业级核心板高温运行测试

Rockchip RK3568 是一款通用型MPU&#xff0c;产品集成GPU、NPU&#xff0c;支持4K、HDMI、LVDS、MIPI、PCIe3.0、USB3.0、千兆以太网、CAN-BUS、UART等丰富外设接口。 RK3568的高温工作情况如何呢&#xff1f;本文将基于万象奥科HD-RK3568-CORE 系列核心板做详细高温测试&…

接口幂等性设计

幂等性: 对于同一个操作发起一次请求或者多次请求&#xff0c;得到的结果都是一样的&#xff0c;不会因为请求多次而出现异常现象。 场景: 用户多次请求&#xff0c;比如重复点击页面上的按钮网络异常&#xff0c;右移网络原因导致在一定时间内未返回调用成功的信息&#xff…