第四章:角色和菜单管理功能【基于Servlet+JSP的图书管理系统】

news2024/9/24 21:21:38

角色和菜单功能

在这里插入图片描述

一、角色功能

  接下来我们可以完成角色管理的增删改查操作

1. Bean对象

  创建sys_role对应的实体对象SysRole

@Data
public class SysRole {

    private Integer id;

    private String name;

    private String notes;

    private Date createTime;
}

2. Dao层

  现在我们就可以在Dao层创建涉及相关的数据库操作的方法。

public interface IRoleDao {
    /**
     * 查询所有的用户信息
     * @return
     */
    public List<SysRole> list(SysRole entity);

    /**
     * 分页查询的方法
     * @param pageUtils 分页数据
     * @return
     */
    public List<SysRole> listPage(PageUtils pageUtils);

    public int save(SysRole entity);

    public SysRole findById(int id);

    public int updateById(SysRole entity);

    int deleteById(int id);

    int count(PageUtils pageUtils);
}

然后是具体的实现

public class RoleDaoImpl implements IRoleDao {
    @Override
    public List<SysRole> list(SysRole entity) {
        QueryRunner queryRunner = MyDbUtils.getQueryRunner();
        String sql = "select * from sys_role ";
        try {
            List<SysRole> list = queryRunner.query(sql, new ResultSetHandler<List<SysRole>>() {
                @Override
                public List<SysRole> handle(ResultSet resultSet) throws SQLException {
                    // 存储返回结果的容器
                    List<SysRole> list = new ArrayList<>();
                    while(resultSet.next()){
                        // 每次循环一次 user 存储一条数据
                        SysRole entity = new SysRole();
                        entity.setId(resultSet.getInt("id"));
                        entity.setName(resultSet.getString("name"));
                        entity.setNotes(resultSet.getString("notes"));
                        entity.setCreateTime(resultSet.getDate("create_time"));
                        list.add(entity); // 把查询的记录封装到了集合容器中
                    }
                    return list; // 返回查询的结果
                }
            });
            return list;
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return null;
    }

    @Override
    public List<SysRole> listPage(PageUtils pageUtils) {
        QueryRunner queryRunner = MyDbUtils.getQueryRunner();
        String sql = "select * from sys_role limit ?,?";
        if(StringUtils.isNotEmpty(pageUtils.getKey())){
            // 需要带条件查询
            sql = "select * from sys_role where name like '%"+pageUtils.getKey()+"%' or notes like '%"+pageUtils.getKey()+"%'  limit ?,?";
        }

        // 计算 分页开始的位置
        int startNo = pageUtils.getStart();
        try {
            // BeanListHandler 会自动的帮助我们完成字段和属性的映射。前提是属性和字段完全一直
            // 此处不会通过驼峰命名法 装换
            // List<SysUser> list = queryRunner.query(sql, new BeanListHandler<SysUser>(SysUser.class));
            List<SysRole> list = queryRunner.query(sql, new ResultSetHandler<List<SysRole>>() {
                @Override
                public List<SysRole> handle(ResultSet resultSet) throws SQLException {
                    // 存储返回结果的容器
                    List<SysRole> list = new ArrayList<>();
                    while(resultSet.next()){
                        // 每次循环一次 user 存储一条数据
                        SysRole entity = new SysRole();
                        entity.setId(resultSet.getInt("id"));
                        entity.setName(resultSet.getString("name"));
                        entity.setNotes(resultSet.getString("notes"));
                        entity.setCreateTime(resultSet.getDate("create_time"));
                        list.add(entity); // 把查询的记录封装到了集合容器中
                    }
                    return list; // 返回查询的结果
                }
            },startNo,pageUtils.getPageSize());
            return list;
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return null;
    }

    @Override
    public int save(SysRole entity) {
        QueryRunner queryRunner = MyDbUtils.getQueryRunner();
        String sql = "insert into sys_role(name,notes) values(?,?)";
        try {
            return queryRunner.update(sql,entity.getName(),entity.getNotes());
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return 0;
    }

    @Override
    public SysRole findById(int id) {
        QueryRunner queryRunner = MyDbUtils.getQueryRunner();
        String sql = "select * from sys_role where id = ? ";
        try {
            return queryRunner.query(sql, new ResultSetHandler<SysRole>() {
                @Override
                public SysRole handle(ResultSet resultSet) throws SQLException {
                    // 存储返回结果的容器
                    if(resultSet.next()){
                        // 每次循环一次 user 存储一条数据
                        SysRole entity = new SysRole();
                        entity.setId(resultSet.getInt("id"));
                        entity.setName(resultSet.getString("name"));
                        entity.setNotes(resultSet.getString("notes"));
                        entity.setCreateTime(resultSet.getDate("create_time"));
                        return entity;
                    }
                    return null; // 返回查询的结果
                }
            },id);

        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return null;
    }

    @Override
    public int updateById(SysRole entity) {
        QueryRunner queryRunner = MyDbUtils.getQueryRunner();
        String sql = "update sys_role set name = ? ,notes=? where id = ?";
        try {
            return queryRunner.update(sql,entity.getName(),entity.getNotes(),entity.getId());
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return 0;
    }

    @Override
    public int deleteById(int id) {
        QueryRunner queryRunner = MyDbUtils.getQueryRunner();
        String sql = "delete from sys_role  where id = ?";
        try {
            return queryRunner.update(sql,id);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return 0;
    }

    @Override
    public int count(PageUtils pageUtils) {
        QueryRunner queryRunner = MyDbUtils.getQueryRunner();
        String sql = "select count(1) from sys_role ";
        if(StringUtils.isNotEmpty(pageUtils.getKey())){
            sql = "select count(1) from sys_role where username like '%"+pageUtils.getKey()+"%' or nickname like '%"+pageUtils.getKey()+"%' ";
        }
        try {
            return queryRunner.query(sql, new ResultSetHandler<Integer>() {
                @Override
                public Integer handle(ResultSet resultSet) throws SQLException {
                    resultSet.next();
                    return resultSet.getInt(1);
                }
            });
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return 0;
    }
}

3. Service层

  添加角色管理的Service相关的代码

public interface IRoleService {

    public List<SysRole> list(SysRole entity);

    public int save(SysRole entity);

    public SysRole findById(int id);

    public int updateById(SysRole entity);

    int deleteById(int id);

    void listPage(PageUtils pageUtils);

    int count(PageUtils pageUtils);
}

  具体接口对应的实现类

public class RoleServiceImpl implements IRoleService {

    private IRoleDao dao = new RoleDaoImpl();

    @Override
    public List<SysRole> list(SysRole entity) {
        return dao.list(entity);
    }

    @Override
    public int save(SysRole entity) {
        return dao.save(entity);
    }

    @Override
    public SysRole findById(int id) {
        return dao.findById(id);
    }

    @Override
    public int updateById(SysRole entity) {
        return dao.updateById(entity);
    }

    @Override
    public int deleteById(int id) {
        return dao.deleteById(id);
    }

    @Override
    public void listPage(PageUtils pageUtils) {
        // 查询分页的数据
        List<SysRole> list = dao.listPage(pageUtils);
        // 查询 满足查询条件的记录数
        int count = dao.count(pageUtils);
        // 封装分页的数据
        pageUtils.setList(list);
        pageUtils.setTotalCount(count);
    }

    @Override
    public int count(PageUtils pageUtils) {
        return dao.count(pageUtils);
    }
}

4. Servlet层

  RoleServlet需要继承前面定义的BaseServlet,然后重写定义的抽象方法。同时要重写list方法。具体如下:

@WebServlet(name = "roleServlet",urlPatterns = {"/sys/roleServlet"})
public class RoleServlet extends BaseServlet{

    private IRoleService service = new RoleServiceImpl();

    @Override
    public void list(HttpServletRequest req, HttpServletResponse resp) throws Exception {
        super.list(req, resp); // 封装了分页的相关的操作
        // TODO 写我们自己的查询处理
        service.listPage(pageUtils);
        req.setAttribute(Constant.LIST_PAGE_UTILS,pageUtils);
        // 页面跳转
        req.getRequestDispatcher("/sys/role/list.jsp").forward(req,resp);
    }

    @Override
    public void saveOrUpdatePage(HttpServletRequest req, HttpServletResponse resp) throws Exception {

    }

    @Override
    public void saveOrUpdate(HttpServletRequest req, HttpServletResponse resp) throws Exception {

    }

    @Override
    public void remove(HttpServletRequest req, HttpServletResponse resp) throws Exception {

    }

    @Override
    public void findById(HttpServletRequest req, HttpServletResponse resp) throws Exception {

    }


}

5. 角色查询

  展示角色数据,那么我们需要做的操作:

  • 修改main.jsp中的跳转地址
  • 修改/sys/role/list.jsp中的访问地址和table数据

在这里插入图片描述

在这里插入图片描述

6. 添加和更新

  添加和删除功能是类似的。我们一块来实现,在Servlet中完善进入添加更新页面的方法和保存和更新的方法的逻辑

@Override
public void saveOrUpdatePage(HttpServletRequest req, HttpServletResponse resp) throws Exception {
    // 如果是更新。需要查询出当前的信息
    String id = req.getParameter("id");
    if(StringUtils.isNotEmpty(id)){
        // 说明是更新
        SysRole entity = service.findById(Integer.parseInt(id));
        req.setAttribute("entity",entity);
    }
    req.getRequestDispatcher("/sys/role/addOrUpdate.jsp").forward(req,resp);
}

@Override
public void saveOrUpdate(HttpServletRequest req, HttpServletResponse resp) throws Exception {
    // 获取提交的数据
    String id = req.getParameter("id");
    String name = req.getParameter("name");
    String notes = req.getParameter("notes");
    SysRole entity = new SysRole();
    entity.setNotes(notes);
    entity.setName(name);
    if(StringUtils.isNotEmpty(id)){
        // 更新
        entity.setId(Integer.parseInt(id));
        service.updateById(entity);
    }else {
        // 保存数据
        service.save(entity);
    }
    // 做重定向查询
    resp.sendRedirect("/sys/roleServlet?action=list");

}

然后就是对应的页面处理

<form class="form-horizontal m-t" id="signupForm" action="/sys/roleServlet?action=saveOrUpdate" method="post">
    <input type="hidden" name="id" value="${entity.id}">
    <div class="form-group">
        <label class="col-sm-3 control-label">名称:</label>
        <div class="col-sm-8">
            <input id="name" name="name" class="form-control" value="${entity.name}"
                   type="text" aria-required="true" aria-invalid="true" class="error">
        </div>
    </div>
    <div class="form-group">
        <label class="col-sm-3 control-label">描述:</label>
        <div class="col-sm-8">
            <input id="notes" name="notes" class="form-control" value="${entity.notes}"
                   type="textarea" aria-required="true" aria-invalid="false" class="valid">
        </div>
    </div>
    <div class="form-group">
        <div class="col-sm-8 col-sm-offset-3">
            <button class="btn btn-default" οnclick="resetPage()" type="button">取消</button>
            <button class="btn btn-primary" type="submit">提交</button>
        </div>
    </div>
</form>

这样就OK了
在这里插入图片描述

7.删除角色

  删除角色我们需要做一个判断。也就是已经分配给用户的角色是不能被删除的。所以删除操作的时候我们需要添加这样一个判断

@Override
public void remove(HttpServletRequest req, HttpServletResponse resp) throws Exception {
    // 删除角色信息
    String id = req.getParameter("id");
    // 删除角色信息 我们需要做校验  如果该角色已经分配给了用户。那么这个角色就不能被删除
    boolean flag = service.checkRoleDispatch(Integer.parseInt(id));
    PrintWriter writer = resp.getWriter();
    if(flag){
        // 表示没有被分配,可以删除
        service.deleteById(Integer.parseInt(id));
        writer.write("ok");
    }else{
        // 表示不能被删除
        writer.write("error");
    }
    writer.flush();
    writer.close();
}

service中的处理

@Override
public boolean checkRoleDispatch(int roleId) {
    SysUser entity = new SysUser();
    entity.setRoleId(roleId);
    return userService.list(entity).size() == 0 ?true:false;
}

这个是在UserService的基础上做的扩展,实现了方法的复用。
在这里插入图片描述

在前端页面的处理上。加了条件判断。

function removeData(id) {
    swal({
        title: "您确定要删除这条信息吗",
        text: "删除后将无法恢复,请谨慎操作!",
        type: "warning",
        showCancelButton: true,
        confirmButtonColor: "#DD6B55",
        confirmButtonText: "删除",
        closeOnConfirm: false
    }, function () {

        $.get("/sys/roleServlet?action=remove&id=" + id, function (msg) {
            if(msg === 'ok'){
                // 表示删除成功
                // 再发起一个查询的操作
                window.location.href = "/sys/roleServlet?action=list"
            }else{
                // 表示不能被删除
                swal("删除失败!", "该角色已经被分配, 不能删除!!!。", "warning");
            }

        })
    });
}

在这里插入图片描述

二、菜单功能

1.查询功能

  系统左侧菜单栏我们需要做成动态的。那么就需要维护相关的菜单数据。所以设计了sys_menu这张表。具体的实现。如下,先定义SysMenu这个实体

@Data
public class SysMenu {

    private Integer id;
    private String name;
    private String url;
    private Integer parentId;
    private int seq;
    private Date createTime;
}

然后维护DAO,ServiceServlet的逻辑。

@WebServlet(name = "menuServlet",urlPatterns = {"/sys/menuServlet"})
public class MenuServlet extends BaseServlet{

    private IMenuService service = new MenuServiceImpl();

    /**
     * 菜单功能不做分页
     * @param req
     * @param resp
     * @throws Exception
     */
    @Override
    public void list(HttpServletRequest req, HttpServletResponse resp) throws Exception {
        List<SysMenu> list = service.list(null);
        req.setAttribute("list",list);
        req.getRequestDispatcher("/sys/menu/list.jsp").forward(req,resp);
    }

    @Override
    public void saveOrUpdatePage(HttpServletRequest req, HttpServletResponse resp) throws Exception {

    }

    @Override
    public void saveOrUpdate(HttpServletRequest req, HttpServletResponse resp) throws Exception {

    }

    @Override
    public void remove(HttpServletRequest req, HttpServletResponse resp) throws Exception {

    }

    @Override
    public void findById(HttpServletRequest req, HttpServletResponse resp) throws Exception {

    }
}

然后页面的展示处理。注意main.jsp的菜单地址和/sys/menu/list.jsp页面的调整,我们在此处没有做分页的处理操作。

在这里插入图片描述

2.添加和更新

  添加和更新处理很类似。我们一并的实现。添加和更新我们已经在用户管理角色管理中已经实现了。所以在此处的难度就降低了很多。步骤一样

  1. 进入登录页面:需要准备相关的数据(根据Id查询信息和查询所有的父菜单信息)
  2. 提交表单数据:后端服务获取数据后做添加和更新的操作

在此处需要注意的是:父菜单分配功能,需要使用到下拉菜单
在这里插入图片描述

对应的代码

<div class="form-group">
    <label class="col-sm-3 control-label">父菜单:</label>
    <div class="col-sm-8">
        <select class="form-control m-b" name="parentId">
            <option value="-1">---本身就是父菜单---</option>
            <c:forEach items="${parents}" var="parent">
                <option value="${parent.id}" ${parent.id == entity.parentId?'selected':''}>${parent.name}</option>
            </c:forEach>
        </select>
    </div>
</div>

表单的提交功能。后端处理数据

@Override
public void saveOrUpdate(HttpServletRequest req, HttpServletResponse resp) throws Exception {
    // 获取表单提交的数据
    String id = req.getParameter("id");
    String name = req.getParameter("name");
    String url = req.getParameter("url");
    String seq = req.getParameter("seq");
    String parentId = req.getParameter("parentId");
    SysMenu menu = new SysMenu();
    menu.setName(name);
    menu.setUrl(url);
    if(StringUtils.isNotEmpty(seq)){
        menu.setSeq(Integer.parseInt(seq));
    }
    if(StringUtils.isNotEmpty(parentId)){
        menu.setParentId(Integer.parseInt(parentId));
    }
    if(StringUtils.isNotEmpty(id)){
        // 更新
        menu.setId(Integer.parseInt(id));
        service.updateById(menu);
    }else{
        // 添加
        service.save(menu);
    }
    resp.sendRedirect("/sys/menuServlet?action=list");
}

功能搞定

3.菜单数据展示

  菜单数据有父子菜单的关系。所以在展示数据的时候需要体现这种关系。我们可以通过双重循环的方式来实现。效果如下:
在这里插入图片描述

同时我们可以通过序号来控制菜单的显示的顺序。关键是在查询的时候通过seq升序查询

在这里插入图片描述

4.删除菜单

  删除菜单本身很简单。但是我们要考虑父子菜单的关系和菜单被分配给角色的情况。那么有些情况是不能被删除的。所以我们在Servlet中需要做相关的判断校验

@Override
public void remove(HttpServletRequest req, HttpServletResponse resp) throws Exception {
    int id = Integer.parseInt(req.getParameter("id"));
    // 删除菜单的判断
    // 1.菜单如果分配给了角色就不能被删除
    boolean flag = service.isDispatcher(id);
    String msg = "ok";
    if(flag){
        // 表示已经被分配了
        msg = "error";
    }else{
        SysMenu entity = service.findById(id);
        // 2.需要删除的菜单是父菜单
        if(entity.getParentId() == -1){
            // 有子菜单的父菜单不能被删除 -- 判断是否有子菜单
            flag = service.haveSubMenu(id);
            if(flag){
                // 有子菜单
                msg = "error";
            }else{
                // 父菜单没有子菜单 可以删除
                service.deleteById(id);
            }
        }else{
            // 3.子菜单 可以被删除
            service.deleteById(id);
        }
    }
    PrintWriter writer = resp.getWriter();
    writer.write(msg);
    writer.flush();
}

三、动态绑定

  实现用户和角色的绑定以及角色和菜单的绑定。实现整个系统动态功能分配管理的效果。

1.角色和菜单

  角色和菜单是多对多的关联关系。所以我们通过sys_role_menu来维护他们之间的关联关系。我们在更新角色信息的时候来维护菜单信息。

在这里插入图片描述

需要注意的地方,在jsp页面中展示数据注意样式

在这里插入图片描述

在展示数据的时候我们在进入更新页面前需要对菜单数据做处理

  1. 查询所以的菜单信息
  2. 对当前角色具有的菜单需要标识

在这里插入图片描述

保存更新数据的逻辑。针对菜单我们的步骤是:

  1. 先删除该角色的所有菜单
  2. 新增分配的菜单信息

在这里插入图片描述

2.用户和角色

  用户和角色是一对一的关联关系,那么这块我们就可以在添加和更新用户的时候直接分配角色信息,这块我们操作的内容:

  1. 进入更新/添加界面前需要查询所有的角色信息
  2. 在更新/添加界面中我们需要添加一个下拉菜单来处理分配功能
  3. 表单数据提交到后台Servlet中我们需要处理角色相关的数据。同时调整前面写的JDBC的方法

在这里插入图片描述

然后对应的表单代码

<div class="form-group">
    <label class="col-sm-3 control-label">分配角色:</label>
    <div class="col-sm-8">
        <select class="form-control m-b" name="roleId">
            <c:forEach items="${requestScope.roles}" var="role">
                <option value="${role.id}" ${role.id == entity.roleId?'selected':''}>${role.name}</option>
            </c:forEach>
        </select>
    </div>
</div>

后端的处理代码

在这里插入图片描述

在这里插入图片描述

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

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

相关文章

JVM(Java虚拟机)详解

目录 一、JVM内存区域划分 1. 什么是内存区域划分以及为啥要进行区域划分 2. JVM内存区域划分详解 3. 堆区详解&#xff1a; 4. 给一段代码&#xff0c;问某个变量是在那个区域上&#xff1f; 二、JVM类加载机制 1.类加载的过程 2. 类加载的时机 3. 双亲委派模型&#xff08…

下班前几分钟,我彻底玩懂了tmux

目录 1. tmux简介2. Session3. Window4. Pane5. 自定义tmux配置6. 在shell脚本中操纵tmuxReferences 1. tmux简介 tmux&#xff08;terminal multiplexer&#xff09;是一个非常强大的工具&#xff0c;主要有以下几点功能&#xff1a; 终端复用&#xff1a; tmux 使你能够在一…

Linux分布式应用 Zabbix监控配置[添加主机 自定义监控内容 邮件报警 自动发现/注册 代理服务器 高可用集群]

-------------------- 添加 zabbix 客户端主机 -------------------- 关闭防火墙 systemctl disable --now firewalld setenforce 0 hostnamectl set-hostname zbx-agent01 服务端和客户端都配置时间同步 yum install -y ntpdate ntpdate -u ntp.aliyun.com 服务端和客户端都设…

基于simulink跟踪火车站对象检测遗弃物体(附源码)

一、前言 此示例演示如何跟踪火车站的对象并确定哪些对象保持静止。公共场所的遗弃物品会引起当局的关注&#xff0c;因为它们可能会构成安全风险。算法&#xff08;例如本例中使用的算法&#xff09;可用于通过将他们的注意力引导到潜在的感兴趣区域来协助监控实时监控视频的…

二十五、传输层协议(上)

文章目录 一、再谈端口号&#xff08;一&#xff09;端口号定义&#xff08;二&#xff09;端口号范围划分1.一共有 2^16 个端口2.认识知名端口号(Well-Know Port Number)3.端口号和进程就是K-V关系4.netstat&#xff08;1&#xff09;示例1&#xff1a; n 拒绝显示别名&#x…

CentOS Linux上安装JDK11、MySQL8.0、Minio等软件(rpm脚本模式)

本地环境&#xff1a;Windows 10家庭版 16G内存 512G硬盘 软件&#xff1a;VMWare WorkStation 16.0 FinalShell 4.0.1 一、下载必要软件包 下载软件均选择x86架构64位&#xff01;&#xff01;&#xff01;&#xff08;可根据自己的电脑配置选择&#xff09; CentOS Linu…

基础算法-前缀和

1 算法笔记 2.代码示例 3.代码解析 #include<iostream> using namespace std; const int maxn 1010000; int a[maxn],s[maxn];//a数组是用来存放数组的&#xff0c;s是用来存放前n项数组的和 int m,n;int main(){scanf("%d%d",&n,&m);for(int i1;i&l…

【react】插件react-tsparticles和tsparticles实现粒子特效:

文章目录 一、效果图:二、实现思路:三、实现代码:【1】安装依赖【2】 一、效果图: 二、实现思路: particles&#xff08;npm i react-particles-js&#xff09;目前已被弃用&#xff1b;取代它的是tsparticles&#xff08;npm i react-tsparticles 和npm install tsparticles&a…

docker 安装应用

前文介绍&#xff1a;我们再阿里云领取的ECS服务器&#xff0c;服务器选择应用模板&#xff0c;他会自动帮我们的服务器安装docker的一些相关插件。如果没有&#xff0c;则需要自己安装docker docker 安装Jenkins 1.下载Jenkins镜像 推荐版本 jenkins/jenkins:lts 命令&…

python 实现简易的学员管理系统

文章目录 前言基本思路需求实现1.实现菜单的功能2.提示用户输入需要进行的操作&#xff0c;并执行相关操作3.具体函数功能的实现增加学员信息显示所有学员信息删除学员信息修改学员信息查询学员信息 整体代码展示 前言 前面我们已经学习了 python 的输入输出、条件语句、循环、…

面向对象编程主线三

面向对象编程 三、第三阶段 高内聚&#xff1a;类的内部数据操作细节自己完成&#xff0c;不允许外部干涉&#xff1b; 低耦合&#xff1a;仅对外暴露少量的方法用于使用。 封装性的设计思想&#xff1a;把该隐藏的隐藏起来&#xff0c;该暴露的暴露出来。 3.1、面向对象的特…

[物理层]传输方式

传输方式 串行传输与并行传输 穿行传输是指数据是一个比特一个比特依次发送的&#xff0c;在发送端与接收端只用一条数据线路 并行传输是指一次发n个比特&#xff0c;在发送端与接收端需要n条数据线路 在网络中计算机通信通常采用串行传输&#xff1b;而在计算机内部&#x…

Minio在Windows的部署并使用Python来操作桶

什么是Minio? MinIO 是一个开源的对象存储服务器&#xff0c;具有高可用性、高性能和可伸缩性。它兼容 Amazon S3 API&#xff0c;因此可以无缝地替代 Amazon S3 作为对象存储的解决方案。 MinIO 可以让你在自己的基础设施中搭建一个对象存储服务&#xff0c;使你能够存储和…

HTML5+CSS3+JS小实例:背景动态变化的登录界面2.0

实例:背景动态变化的登录界面2.0 技术栈:HTML+CSS+JS 效果: 源码: 【html】 <!DOCTYPE html> <html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"><meta name="viewport" con…

malloc()与calloc()的辨析

malloc()与calloc()的相同点 两者都是常用的内存分配函数&#xff0c;用于动态分配内存 两者返回值类型都为void*&#xff0c;需要强制转换为所需类型 使用完分配的内存后&#xff0c;都需使用free()函数来释放该内存&#xff0c;防止内存泄漏 malloc()与calloc()的不同点 mal…

你可能不知道现在的Java面试有多卷

大家好&#xff0c;最近有不少小伙伴在后台留言&#xff0c;今年面试实在是太卷了&#xff0c;不知道从何下手&#xff01; 不论是跳槽涨薪&#xff0c;还是学习提升&#xff01;先给自己定一个小目标&#xff0c;然后再朝着目标去努力就完事儿了&#xff01; 为了帮大家节约…

threejs 音频可视化demo

效果&#xff1a; 在线效果预览&#xff1a;Vite App 源码&#xff1a;https://github.com/developer-wgl/ThreeJsDemo 参考&#xff1a;three.js 音乐可视化_threejs音乐可视化_汉武大帝的博客-CSDN博客

谈谈——互联网生活中的隐私保护

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

Unity VR:Oculus Integration 中 OVRManager 的 Eye Level,Floor Level,Stage 的区别

Oculus Integration 开发包中有个 OVRManager 脚本被挂载到 OVRCameraRig 物体上。OVR Manager 中有个 Tracking Origin Type 参数&#xff0c;它相当于追踪的参考系&#xff0c;参数分为 Eye Level, Floor Level 和 Stage。 VR 设备会对头显进行追踪&#xff0c;于是现实中头显…