day05_用户管理minIO角色分配(页面制作,查询用户,添加用户,修改用户,删除用户,用户头像,查询所有角色,保存角色数据)

news2024/10/5 21:22:47

文章目录

  • 1 用户管理
    • 1.1 页面制作
    • 1.2 查询用户
      • 1.2.1 需求说明
      • 1.2.2 后端接口
        • 需求分析
        • SysUser
        • SysUserDto
        • SysUserController
        • SysUserService
        • SysUserMapper
        • SysUserMapper.xml
      • 1.2.3 前端对接
        • 实现思路
        • sysUser.js
        • sysRole.vue
    • 1.3 添加用户
      • 1.3.1 需求说明
      • 1.3.2 页面制作
      • 1.3.3 后端接口
        • SysUserController
        • SysUserService
        • SysUserMapper
        • SysUserMapper.xml
      • 1.3.4 前端对接
        • 实现思路
        • sysUser.js
        • sysRole.vue
    • 1.4 修改用户
      • 1.4.1 需求说明
      • 1.4.2 数据回显
      • 1.4.3 提交修改
        • 后端接口
          • SysUserController
          • SysUserService
          • SysUserMapper
          • SysUserMapper.xml
        • 前端对接
          • sysUser.js
          • sysUser.vue
    • 1.5 删除用户
      • 1.5.1 需求说明
      • 1.5.2 后端接口
        • SysRoleController
        • SysRoleService
        • SysRoleMapper
        • SysRoleMapper.xml
      • 1.5.3 前端对接
        • sysUser.js
        • sysUser.vue
  • 2 用户头像
    • 2.1 需求分析
    • 2.2 文件存储方案
    • 2.3 Minio使用
      • 2.3.1 Minio介绍
      • 2.3.2 MinIO安装
      • 2.3.3 Minio入门
    • 2.4 上传文件接口
      • 2.4.1 FileUploadController
      • 2.4.2 FileUploadService
      • 2.4.3 MinioProperties
      • 2.4.4 配置文件内容
    • 2.5 前端对接
  • 3 分配角色
    • 3.1 需求分析
    • 3.2 页面制作
    • 3.3 查询所有角色
      • 3.3.1 后端接口
        • SysRole
        • SysRoleController
        • SysRoleService
        • SysRoleMapper
        • SysRoleMapper.xml
      • 3.3.2 前端对接
        • sysRole.js
        • sysUser.vue
    • 3.4 保存角色数据
      • 3.4.1 后端接口
        • AssginRoleDto
        • SysRoleUser
        • SysRoleUserController
        • SysRoleUserService
        • SysRoleUserMapper
        • SysRoleUserMapper.xml
      • 3.4.2 前端对接
        • sysUser.js
        • sysUser.vue
      • 3.4.2 前端对接
        • sysUser.js
        • sysUser.vue

1 用户管理

用户管理就是对后台管理系统的使用用户进行维护。

1.1 页面制作

对比如下页面结构,使用Element Plus制作出对应的页面,数据可以暂时使用假数据。

在这里插入图片描述

该页面可以将其分为4部分:

1、搜索表单

2、添加按钮

3、数据展示表格

4、分页条组件

代码实现如下所示:

<template>

    <!---搜索表单-->
    <div class="search-div">
        <el-form label-width="70px" size="small">
            <el-row>
                <el-col :span="12">
                <el-form-item label="关键字">
                    <el-input
                    style="width: 100%"
                    placeholder="用户名、姓名、手机号码"
                    ></el-input>
                </el-form-item>
                </el-col>
                <el-col :span="12">
                <el-form-item label="创建时间">
                    <el-date-picker
                    type="daterange"
                    range-separator="To"
                    start-placeholder="开始时间"
                    end-placeholder="结束时间"
                    format="YYYY-MM-DD"
                    value-format="YYYY-MM-DD"
                    />
                </el-form-item>
                </el-col>
            </el-row>
            <el-row style="display:flex">
                <el-button type="primary" size="small">
                搜索
                </el-button>
                <el-button size="small">重置</el-button>
            </el-row>
        </el-form>
    </div>

    <!--添加按钮-->
    <div class="tools-div">
        <el-button type="success" size="small">添 加</el-button>
    </div>

    <!---数据表格-->
    <el-table :data="list" style="width: 100%">
        <el-table-column prop="userName" label="用户名" />
        <el-table-column prop="name" label="姓名" />
        <el-table-column prop="phone" label="手机" />
        <el-table-column prop="avatar" label="头像" #default="scope">
            <img :src="scope.row.avatar" width="50" />
        </el-table-column>
        <el-table-column prop="description" label="描述" />
        <el-table-column prop="status" label="状态" #default="scope">
            {{ scope.row.status == 1 ? '正常' : '停用' }}
        </el-table-column>
        <el-table-column prop="createTime" label="创建时间" />
        <el-table-column label="操作" align="center" width="280" >
            <el-button type="primary" size="small">
                修改
            </el-button>
            <el-button type="danger" size="small">
                删除
            </el-button>
            <el-button type="warning" size="small">
                分配角色
            </el-button>
        </el-table-column>
    </el-table>

    <el-pagination
        :page-sizes="[10, 20, 50, 100]"
        layout="total, sizes, prev, pager, next"
        :total="total"
    />

</template>

<script setup>
import { ref } from 'vue'; 

// 表格数据模型
const list = ref([
    {"id":1 , "userName":"admin" , "name": "admin" , "phone":"13121034567" , "status":1 , "createTime": "2023-05-11"} ,
    {"id":2 , "userName":"admin" , "name": "admin" , "phone":"13121034567" , "status":1 , "createTime": "2023-05-11"} 
]);

// 分页条数据模型
const total = ref(0)

</script>

<style scoped>
.search-div {
  margin-bottom: 10px;
  padding: 10px;
  border: 1px solid #ebeef5;
  border-radius: 3px;
  background-color: #fff;
}
.tools-div {
  margin: 10px 0;
  padding: 10px;
  border: 1px solid #ebeef5;
  border-radius: 3px;
  background-color: #fff;
}
</style>
<style scoped>
.avatar-uploader .avatar {
  width: 178px;
  height: 178px;
  display: block;
}
</style>

<style>
.avatar-uploader .el-upload {
  border: 1px dashed var(--el-border-color);
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: var(--el-transition-duration-fast);
}

.avatar-uploader .el-upload:hover {
  border-color: var(--el-color-primary);
}

.el-icon.avatar-uploader-icon {
  font-size: 28px;
  color: #8c939d;
  width: 178px;
  height: 178px;
  text-align: center;
}
</style>

1.2 查询用户

1.2.1 需求说明

需求说明:

1、如果在搜索表单中输入和查询关键字以及创建的开始时间和结束是时间,那么此时就需要按照查询关键字以及创建的开始时间和结束是时间进行条件查询

2、查询关键字搜索的字段可以是用户名、姓名、手机号码。在查询的时候需要继续按照这些字段进行模糊查询。

2、搜索的时候需要进行分页搜索

1.2.2 后端接口

需求分析

1、前端提交请求参数的时候包含了两部分的参数:搜索条件参数、分页参数。搜索条件参数可以通过?拼接到请求路径后面,分页参数【当前页码、每页显示的数据条数】可以让前端通过请求路径传递过来

2、后端查询完毕以后需要给前端返回一个分页对象,分页对象中就封装了分页相关的参数(当前页数据、总记录数、总页数…)

3、前端进行参数传递的时候,不一定会传递搜索条件,因此sql语句的编写需要使用到动态sql

SysUser

针对当前要操作的数据库表定义一个与之对应的实体类:

// com.atguigu.spzx.model.entity.system
@Data
public class SysUser extends BaseEntity {

	private static final long serialVersionUID = 1L;
	private String userName;
	private String password;
	private String name;
	private String phone;
	private String avatar;
	private String description;
	private Integer status;

}
SysUserDto

定义一个实体类用来封装前端所传递过来的查询参数,具体定义如下所示:

// com.atguigu.spzx.model.dto.system
@Data
public class SysUserDto {

    private String keyword ;
    private String createTimeBegin ;
    private String createTimeEnd;

}
SysUserController

表现层代码:

// com.atguigu.spzx.manager.controller
@RestController
@RequestMapping(value = "/admin/system/sysUser")
public class SysUserController {

    @Autowired
    private SysUserService sysUserService ;

    @GetMapping(value = "/findByPage/{pageNum}/{pageSize}")
    public Result<PageInfo<SysRole>> findByPage(SysUserDto sysUserDto ,
                                                @PathVariable(value = "pageNum") Integer pageNum ,
                                                @PathVariable(value = "pageSize") Integer pageSize) {
        PageInfo<SysUser> pageInfo = sysUserService.findByPage(sysUserDto , pageNum , pageSize) ;
        return Result.build(pageInfo , ResultCodeEnum.SUCCESS) ;
    }

}
SysUserService

业务层代码实现

// com.atguigu.spzx.manager.service.impl
@Override
public PageInfo<SysUser> findByPage(SysUserDto sysUserDto, Integer pageNum, Integer pageSize) {
    PageHelper.startPage(pageNum , pageSize);
    List<SysUser> sysUserList = sysUserMapper.findByPage(sysUserDto) ;
    PageInfo pageInfo = new PageInfo(sysUserList) ;
    return pageInfo;
}
SysUserMapper

持久层代码实现

@Mapper
public interface SysUserMapper {
    public abstract List<SysUser> findByPage(SysUserDto sysUserDto);
}
SysUserMapper.xml

在映射文件中定义对应的sql语句

<sql id="findPageWhere">
    <where>
        <if test="keyword != null and keyword != ''">
            and (username like CONCAT('%',#{keyword},'%') or name like CONCAT('%',#{keyword} , '%') or phone like CONCAT('%',#{keyword} , '%'))
        </if>
        <if test="createTimeBegin != null and createTimeBegin != ''">
            and create_time >= #{createTimeBegin}
        </if>
        <if test="createTimeEnd != null and createTimeEnd != ''">
            and create_time &lt;= #{createTimeEnd}
        </if>
        and is_deleted = 0
    </where>
</sql>

<select id="findByPage" resultType="com.atguigu.spzx.model.entity.system.SysUser" >
    select <include refid="columns" />
    from sys_user
    <include refid="findPageWhere"/>
    order by id desc
</select>

1.2.3 前端对接

实现思路

如下所示:

1、定义发送请求方法

2、搜索表单绑定对应数据模型

3、onMounted钩子函数发送请求查询数据

4、分页条绑定数据模型以及对应事件

sysUser.js

在api目录下创建一个sysUser.js文件,文件的内容如下所示:

import request from '@/utils/request'

// 分页查询
export const GetSysUserListByPage = (pageNum , pageSize , queryDto) => {
    return request({
        url: "/admin/system/sysUser/findByPage/" + pageNum + "/" + pageSize,
        method: 'get',
        params: queryDto
    })
}
sysRole.vue

更改views/system/sysRole.vue文件

<!-- 搜索表单 -->
<!---搜索表单-->
<div class="search-div">
    <el-form label-width="70px" size="small">
        <el-row>
            <el-col :span="12">
                <el-form-item label="关键字">
                    <el-input v-model="queryDto.keyword"
                              style="width: 100%"
                              placeholder="用户名、姓名、手机号码"
                              ></el-input>
                </el-form-item>
            </el-col>
            <el-col :span="12">
                <el-form-item label="创建时间">
                    <el-date-picker v-model="createTimes"
                                    type="daterange"
                                    range-separator="To"
                                    start-placeholder="开始时间"
                                    end-placeholder="结束时间"
                                    format="YYYY-MM-DD"
                                    value-format="YYYY-MM-DD"
                                    />
                </el-form-item>
            </el-col>
        </el-row>
        <el-row style="display:flex">
            <el-button type="primary" size="small" @click="searchSysUser">
                搜索
            </el-button>
            <el-button size="small" @click="resetData">重置</el-button>
        </el-row>
    </el-form>
</div>  

<!---数据表格-->
<el-table :data="list" style="width: 100%">
    <el-table-column prop="userName" label="用户名" />
    <el-table-column prop="name" label="姓名" />
    <el-table-column prop="phone" label="手机" />
    <el-table-column prop="avatar" label="头像" #default="scope">
        <img :src="scope.row.avatar" width="50" />
    </el-table-column>
    <el-table-column prop="description" label="描述" />
    <el-table-column prop="status" label="状态" #default="scope">
        {{ scope.row.status == 1 ? '正常' : '停用' }}
    </el-table-column>
    <el-table-column prop="createTime" label="创建时间" />
    <el-table-column label="操作" align="center" width="280" >
        <el-button type="primary" size="small">
            修改
        </el-button>
        <el-button type="danger" size="small">
            删除
        </el-button>
        <el-button type="warning" size="small">
            分配角色
        </el-button>
    </el-table-column>
</el-table>

<el-pagination
               v-model:current-page="pageParams.page"
               v-model:page-size="pageParams.limit"
               :page-sizes="[10, 20, 50, 100]"
               layout="total, sizes, prev, pager, next"
               :total="total"
               />

<script setup>
    import { ref , onMounted } from 'vue'; 
    import { GetSysUserListByPage } from '@/api/sysUser';

    // 表格数据模型
    const list = ref([
        {"id":1 , "username":"admin" , "name": "admin" , "phone":"13121034567" , "status":1 , "createTime": "2023-05-11"} ,
        {"id":2 , "username":"admin" , "name": "admin" , "phone":"13121034567" , "status":1 , "createTime": "2023-05-11"} 
    ]);

    // 分页条数据模型
    const total = ref(0)

    // 定义搜索表单数据模型
    const queryDto = ref({
        keyword: "" ,
        createTimeBegin: "",
        createTimeEnd: ""
    })
    const createTimes = ref([])

    //分页数据
    const pageParamsForm = {
        page: 1, // 页码
        limit: 10, // 每页记录数
    }
    const pageParams = ref(pageParamsForm)

    // onMounted钩子函数
    onMounted(() => {
        fetchData() ;
    })

    // 搜素按钮点击事件处理函数
    const searchSysUser = () => {
        fetchData()
    }

    // 重置按钮点击事件处理函数
    const resetData = () => {
        queryDto.value = {}
        createTimes.value = []
    }

    // 定义分页查询方法
    const fetchData = async () => {
        if (createTimes.value.length == 2) {
            queryDto.value.createTimeBegin = createTimes.value[0]
            queryDto.value.createTimeEnd = createTimes.value[1]
        }
        // 请求后端接口进行分页查询
        const { code , message , data } = await GetSysUserListByPage(pageParams.value.page , pageParams.value.limit , queryDto.value)
        list.value = data.list
        total.value = data.total
    }

</script>

1.3 添加用户

1.3.1 需求说明

当用户点击添加按钮的时候,那么此时就弹出对话框,在该对话框中需要展示添加用户表单。当用户在该表单中点击提交按钮的时候那么此时就需要将表单进行提交,在后端需要提交过来的表单数据保存到数据库中即可。页面效果如下所示:

在这里插入图片描述

1.3.2 页面制作

页面代码如下所示:

<!--添加按钮-->
<div class="tools-div">
    <el-button type="success" size="small" @click="addShow">添 加</el-button>
</div>

<el-dialog v-model="dialogVisible" title="添加或修改" width="40%">
    <el-form label-width="120px">
        <el-form-item label="用户名">
            <el-input />
        </el-form-item>
        <el-form-item label="密码">
            <el-input />
        </el-form-item>
        <el-form-item label="姓名">
            <el-input />
        </el-form-item>
        <el-form-item label="手机">
            <el-input />
        </el-form-item>
        <el-form-item label="头像">
            <el-upload
                       class="avatar-uploader"
                       action="http://localhost:8501/admin/system/fileUpload"
                       :show-file-list="false"
                       >
                <img v-if="sysUser.avatar" :src="sysUser.avatar" class="avatar" />
                <el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
            </el-upload>
        </el-form-item>
        <el-form-item label="描述">
            <el-input  />
        </el-form-item>
        <el-form-item>
            <el-button type="primary" >提交</el-button>
            <el-button @click="dialogVisible = false">取消</el-button>
        </el-form-item>
    </el-form>
</el-dialog> 

<script setup>

    // 添加表单对话框显示隐藏控制变量
    const dialogVisible = ref(false)
    const addShow = () => {
        dialogVisible.value = true 
    }

    // 定义提交表单数据模型
    const defaultForm = {
        avatar: ""
    }
    const sysUser = ref(defaultForm)
</script>

1.3.3 后端接口

SysUserController

表现层代码

// com.atguigu.spzx.manager.controller.SysUserController
@PostMapping(value = "/sysUser")
public Result saveSysUser(@RequestBody SysUser sysUser) {
    sysUserService.saveSysUser(sysUser) ;
    return Result.build(null , ResultCodeEnum.SUCCESS) ;
}
SysUserService

业务层代码

// com.atguigu.spzx.manager.service.impl.SysUserServiceImpl
@Override
public void saveSysUser(SysUser sysUser) {

    // 根据输入的用户名查询用户
    SysUser dbSysUser = sysUserMapper.findByUserName(sysUser.getUserName()) ;
    if(dbSysUser != null) {
        throw new GuiguException(ResultCodeEnum.USER_NAME_IS_EXISTS) ;
    }

    // 对密码进行加密
    String password = sysUser.getPassword();
    String digestPassword = DigestUtils.md5DigestAsHex(password.getBytes());
    sysUser.setPassword(digestPassword);
    sysUser.setStatus(0);
    sysUserMapper.saveSysUser(sysUser) ;
}
SysUserMapper

持久层代码

@Mapper
public interface SysUserMapper {
    public abstract SysUser findByUserName(String name);
    public abstract void saveSysUser(SysUser sysUser);
}
SysUserMapper.xml

在映射文件中定义对应的sql语句

<select id="findByUserName" resultType="com.atguigu.spzx.model.entity.system.SysUser">
    select <include refid="columns" /> from sys_user where username = #{userName}
</select>

<insert id="saveSysUser">
    insert into sys_user (
        id,
        username,
        password,
        name,
        phone,
        avatar,
        description,
        status
    ) values (
        #{id},
        #{userName},
        #{password},
        #{name},
        #{phone},
        #{avatar},
        #{description},
        #{status}
    )
</insert>

1.3.4 前端对接

实现思路

1、给表单绑定数据模型

2、给提交按钮绑定点击事件

3、点击按钮请求后端地址

sysUser.js

在api目录下创建一个sysUser.js文件,文件的内容如下所示:

// 新增用户的方法
export const SaveSysUser = (data) => {
    return request({
        url: "/admin/system/sysUser/saveSysUser",
        method: "post",
        data
    })
}
sysRole.vue

更改views/system/sysRole.vue文件,内容如下所示:

<el-dialog v-model="dialogVisible" title="添加或修改" width="40%">
    <el-form label-width="120px">
        <el-form-item label="用户名">
            <el-input v-model="sysUser.userName"/>
        </el-form-item>
        <el-form-item label="密码">
            <el-input type="password" show-password v-model="sysUser.password"/>
        </el-form-item>
        <el-form-item label="姓名">
            <el-input v-model="sysUser.name"/>
        </el-form-item>
        <el-form-item label="手机">
            <el-input v-model="sysUser.phone"/>
        </el-form-item>
        <el-form-item label="头像">
            <el-upload
                       class="avatar-uploader"
                       action="http://localhost:8501/admin/system/fileUpload"
                       :show-file-list="false"
                       >
                <img v-if="sysUser.avatar" :src="sysUser.avatar" class="avatar" />
                <el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
            </el-upload>
        </el-form-item>
        <el-form-item label="描述">
            <el-input  v-model="sysUser.description"/>
        </el-form-item>
        <el-form-item>
            <el-button type="primary" @click="submit">提交</el-button>
            <el-button @click="dialogVisible = false">取消</el-button>
        </el-form-item>
    </el-form>
</el-dialog> 

<script setup>
import { GetSysUserListByPage , SaveSysUser } from '@/api/sysUser';
import { ElMessage, ElMessageBox } from 'element-plus'
    
// 定义提交表单数据模型
const defaultForm = {
    userName:"",
    name: "" ,
    phone: "" ,
    password: "" ,
    description:"",
    avatar: ""
}
const sysUser = ref(defaultForm)

// 提交按钮事件处理函数
const submit = async () => {
    const {code , message , data} = await SaveSysUser(sysUser.value) 
    if(code === 200) {
        dialogVisible.value = false
        ElMessage.success('操作成功')
        fetchData()
    }else {
        ElMessage.error(message)
    }
}
</script>

1.4 修改用户

1.4.1 需求说明

当用户点击修改按钮的时候,那么此时就弹出对话框,在该对话框中需要将当前行所对应的用户数据在该表单页面进行展示。当用户在该表单中点击提

交按钮的时候那么此时就需要将表单进行提交,在后端需要提交过来的表单数据修改数据库中的即可。页面效果如下所示:

在这里插入图片描述

注意:在进行修改的时候密码框不要进行展示,密码不允许进行修改,可以通过v-if进行控制。

1.4.2 数据回显

分析:

1、使用添加数据的表单即可

2、要将当前操作行的数据展示在表单中,那么此时需要用到插槽

代码如下所示:

<el-table-column label="操作" align="center" width="280" #default="scope" >
    <el-button type="primary" size="small" @click="editSysUser(scope.row)">
        修改
    </el-button>
</el-table-column>

<script setup>
    
// 修改按钮点击事件处理函数
const editSysUser = (row) => {
    dialogVisible.value = true 
    sysUser.value = row
}

</script>

1.4.3 提交修改

后端接口
SysUserController

表现层代码

// com.atguigu.spzx.manager.controller.SysUserController
@PutMapping(value = "/updateSysUser")
public Result updateSysUser(@RequestBody SysUser sysUser) {
    sysUserService.updateSysUser(sysUser) ;
    return Result.build(null , ResultCodeEnum.SUCCESS) ;
}
SysUserService

业务层代码

// com.atguigu.spzx.manager.service.impl.SysUserServiceImpl
@Override
public void updateSysUser(SysUser sysUser) {
    sysUserMapper.updateSysUser(sysUser) ;
}
SysUserMapper

持久层代码

// com.atguigu.spzx.manager.mapper.SysUserMapper
public abstract void updateSysUser(SysUser sysUser);
SysUserMapper.xml

映射文件添加如下sql语句:

<update id="updateSysUser">
    update sys_user set
    <if test="userName != null and userName != ''">
        username = #{userName},
    </if>
    <if test="password != null and password != ''">
        password = #{password},
    </if>
    <if test="name != null and name != ''">
        name = #{name},
    </if>
    <if test="phone != null and phone != ''">
        phone = #{phone},
    </if>
    <if test="description != null and description != ''">
        description = #{description},
    </if>
    <if test="status != null and status != ''">
        status = #{status},
    </if>
    update_time =  now()
    where
    id = #{id}
</update>
前端对接
sysUser.js

在api目录下创建一个sysUser.js文件,文件的内容如下所示:

// 修改用户数据的方法
export const UpdateSysUser = (sysUser) => {
    return request({
        url: "/admin/system/sysUser/updateSysUser",
        method: "put",
        data: sysUser
    })
}
sysUser.vue

更改views/system/sysUser.vue文件

<script setup>
import { GetSysUserListByPage , SaveSysUser , UpdateSysUser } from '@/api/sysUser';

// 提交按钮事件处理函数
const submit = async () => {
    if(!sysUser.value.id) {
        const {code , message , data} = await SaveSysUser(sysUser.value) 
        if(code === 200) {
            dialogVisible.value = false
            ElMessage.success('操作成功')
            fetchData()
        }else {
            ElMessage.error(message)
        }

    }else {
        const {code , message , data} = await UpdateSysUser(sysUser.value) 
        if(code === 200) {
            dialogVisible.value = false
            ElMessage.success('操作成功')
            fetchData()
        }else {
            ElMessage.error(message)
        }   
    }
    
}
</script>

1.5 删除用户

1.5.1 需求说明

当点击删除按钮的时候此时需要弹出一个提示框,询问是否需要删除数据?如果用户点击是,那么此时向后端发送请求传递id参数,后端接收id参数进

行逻辑删除。页面效果如下所示:

在这里插入图片描述

1.5.2 后端接口

SysRoleController

表现层代码实现

// com.atguigu.spzx.manager.controller.SysUserController
@DeleteMapping(value = "/deleteById/{userId}")
public Result deleteById(@PathVariable(value = "userId") Long userId) {
    sysUserService.deleteById(userId) ;
    return Result.build(null , ResultCodeEnum.SUCCESS) ;
}
SysRoleService

业务层代码实现

// com.atguigu.spzx.manager.service.impl.SysUserServiceImpl
@Override
public void deleteById(Long userId) {
    sysUserMapper.deleteById(userId) ;
}
SysRoleMapper

持久层代码实现

// com.atguigu.spzx.manager.mapper.SysUserMapper
public abstract void deleteById(Long userId);
SysRoleMapper.xml

在映射文件中添加如下的sql语句:

<delete id="deleteById">
    update sys_user set
    update_time = now() ,
    is_deleted = 1
    where
    id = #{id}
</delete>

1.5.3 前端对接

sysUser.js

在api目录下创建一个sysUser.js文件,文件的内容如下所示:

// 根据id删除用户
export const DeleteSysUserById = (userId) => {
    return request({
        url: "/admin/system/sysUser/deleteById/" + userId,
        method: 'delete'
    })
}
sysUser.vue

更改views/system/sysRole.vue文件

<el-table-column label="操作" align="center" width="280" #default="scope" >
    <el-button type="danger" size="small" @click="deleteById(scope.row)">
        删除
    </el-button>
</el-table-column>

<script setup>
import { GetSysUserListByPage , SaveSysUser , UpdateSysUser , DeleteSysUserById} from '@/api/sysUser';
import { ElMessage, ElMessageBox } from 'element-plus'
    
// 删除角色
const deleteById = (row) => {
    ElMessageBox.confirm('此操作将永久删除该记录, 是否继续?', 'Warning', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
    }).then(async () => {
       const {code } = await DeleteSysUserById(row.id)
       if(code === 200) {
            ElMessage.success('删除成功')
            fetchData()
       }
    }).catch(() => {
        ElMessage.info('取消删除')
    })
}
</script>

2 用户头像

2.1 需求分析

当在进行用户添加的时候,此时可以在添加表单页面点击"+"号,然后选择要上传的用户图像。选择完毕以后,那么此时就会请求后端上传文件接口,

将图片的二进制数据传递到后端。后端需要将数据图片存储起来,然后给前端返回图片的访问地址,然后前端需要将图片的访问地址设置给sysUser数

据模型,当用户点击提交按钮的时候,那么此时就会将表单进行提交,后端将数据保存起来即可。

对应的流程图如下所示:

在这里插入图片描述

2.2 文件存储方案

常见的文件存储方案以及优缺点比较:

方案介绍基本介绍优点缺点
本地文件存储将文件直接存储在服务器本地的硬盘上简单易用,不需要额外的网络设备或服务,可直接读写本地磁盘上的文件。单机存储容量和并发性有限,不具备高可用性和容错能力,可能会影响数据安全和系统稳定性。
分布式文件系统将文件分散存储在多个服务器上,通过网络进行访问和管理。可横向扩展、高可用性、容错能力强,支持大规模数据存储和访问,并提供数据备份和恢复等功能。部署和维护成本较高,对网络通信和硬件环境要求较高。
对象存储服务将文件以对象的形式存储在云服务提供商的存储设施中,并采用HTTP REST API等方式进行访问。可通过HTTP REST API进行访问,具有高可用性、容错能力强,数据安全性好,同时也可以根据实际使用情况灵活调整存储空间和计费方式。上传和下载速度可能受到网络带宽和延迟等因素的影响,并且使用时可能需要付费。

本次我们选择分布式文件系统来存储我们系统中的图片数据。

2.3 Minio使用

2.3.1 Minio介绍

官网:https://www.minio.org.cn/

MinIO是一个开源的分布式对象存储服务器,支持S3协议并且可以在多节点上实现数据的高可用和容错。它采用Go语言开发,拥有轻量级、高性能、易部署等特点,并且可以自由选择底层存储介质。

MinIO的主要特点包括:

1、高性能:MinIO基于GO语言编写,具有高速、轻量级、高并发等性能特点,还支持多线程和缓存等机制进行优化,可以快速地处理大规模数据。

2、可扩展性:MinIO采用分布式存储模式,支持水平扩展,通过增加节点数量来扩展存储容量和性能,支持自动数据迁移和负载均衡。

3、安全性:MinIO提供了多种安全策略,如访问控制列表(ACL)、服务端加密(SSE)、传输层安全性(TLS)等,可以保障数据安全和隐私。

4、兼容性:MinIO兼容AWS S3 API,还支持其他云服务提供商的API,比如GCP、Azure等,可以通过简单的配置实现互操作性。

5、简单易用:MinIO的部署和管理非常简单,只需要运行一个二进制包即可启动服务,同时提供了Web界面和命令行工具等方便的管理工具。

S3协议是Amazon Web Services (AWS) 提供的对象存储服务(Simple Storage Service)的API协议。它是一种 RESTful风格的Web服务接口,使用HTTP/HTTPS协议进行通信,支持多种编程语言和操作系统,并实现了数据的可靠存储、高扩展性以及良好的可用性。

2.3.2 MinIO安装

官网地址:https://www.minio.org.cn/docs/cn/minio/container/index.html

具体命令:

// 创建数据存储目录
mkdir -p ~/minio/data

// 创建minio
docker run \
   -p 9000:9000 \
   -p 9001:9001 \
   --name spzx-minio \
   -v ~/minio/data:/data \
   -e "MINIO_ROOT_USER=admin" \
   -e "MINIO_ROOT_PASSWORD=admin123456" \
   -d \
   quay.io/minio/minio server /data --console-address ":9001"

2.3.3 Minio入门

本章节会给大家介绍一下如何通过Java客户端操作Minio,可以参考官网地址。

官网地址:https://min.io/docs/minio/linux/developers/java/minio-java.html

具体步骤:

1、加入如下依赖

<!-- common-util模块中加入如下依赖 -->
<dependency>
    <groupId>io.minio</groupId>
    <artifactId>minio</artifactId>
    <version>8.5.2</version>
</dependency>

2、示例代码

public class FileUploadTest {

    public static void main(String[] args) throws Exception {

        // 创建一个Minio的客户端对象
        MinioClient minioClient = MinioClient.builder()
                        .endpoint("http://192.168.136.142:9001")
                        .credentials("admin", "admin123456")
                        .build();

        boolean found = minioClient.bucketExists(BucketExistsArgs.builder().bucket("spzx-bucket").build());

        // 如果不存在,那么此时就创建一个新的桶
        if (!found) {
            minioClient.makeBucket(MakeBucketArgs.builder().bucket("spzx-bucket").build());
        } else {  // 如果存在打印信息
            System.out.println("Bucket 'spzx-bucket' already exists.");
        }

        FileInputStream fis = new FileInputStream("D://images//1.jpg") ;
        PutObjectArgs putObjectArgs = PutObjectArgs.builder() 
                .bucket("spzx-bucket")
                .stream(fis, fis.available(), -1)
                .object("1.jpg")
                .build();
        minioClient.putObject(putObjectArgs) ;

        // 构建fileUrl
        String fileUrl = "http://192.168.136.142:9001/spzx-bucket/1.jpg" ;
        System.out.println(fileUrl);

    }

}

注意:设置minio的中该桶的访问权限为public,如下所示:

在这里插入图片描述

2.4 上传文件接口

2.4.1 FileUploadController

上传文件的表现层代码:

@RestController
@RequestMapping("/admin/system")
public class FileUploadController {

    @Autowired
    private FileUploadService fileUploadService ;

    @PostMapping(value = "/fileUpload")
    public Result<String> fileUpload(@RequestParam(value = "file") MultipartFile multipartFile) {
        String fileUrl = fileUploadService.fileUpload(multipartFile) ;
        return Result.build(fileUrl , ResultCodeEnum.SUCCESS) ;
    }

}

2.4.2 FileUploadService

上传文件的业务层代码:

@Service
public class FileUploadServiceImpl implements FileUploadService {

    @Autowired
    private MinioProperties minioProperties ;

    @Override
    public String fileUpload(MultipartFile multipartFile) {

        try {

            // 创建一个Minio的客户端对象
            MinioClient minioClient = MinioClient.builder()
                    .endpoint(minioProperties.getEndpointUrl())
                    .credentials(minioProperties.getAccessKey(), minioProperties.getSecreKey())
                    .build();

            // 判断桶是否存在
            boolean found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(minioProperties.getBucketName()).build());
            if (!found) {       // 如果不存在,那么此时就创建一个新的桶
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(minioProperties.getBucketName()).build());
            } else {  // 如果存在打印信息
                System.out.println("Bucket 'spzx-bucket' already exists.");
            }

            // 设置存储对象名称
            String extFileName = FileNameUtils.getExtension(multipartFile.getOriginalFilename());
            String fileName = new SimpleDateFormat("yyyyMMdd")
                    .format(new Date()) + "/" + UUID.randomUUID().toString().replace("-" , "") + "." + extFileName;

            PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                    .bucket(minioProperties.getBucketName())
                    .stream(multipartFile.getInputStream(), multipartFile.getSize(), -1)
                    .object(fileName)
                    .build();
            minioClient.putObject(putObjectArgs) ;

            return minioProperties.getEndpointUrl() + "/" + minioProperties.getBucketName() + "/" + fileName ;

        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }
}

2.4.3 MinioProperties

将构建MinioClient所对应的参数定义到配置文件中,然后通过该实体类封装该配置文件中的内容。

@Data
@ConfigurationProperties(prefix="spzx.minio") //读取节点
public class MinioProperties {

    private String endpointUrl;
    private String accessKey;
    private String secreKey;
    private String bucketName;

}

2.4.4 配置文件内容

在配置文件中添加Minio的相关配置

# 自定义配置
spzx:
  minio:
    endpointUrl: http://192.168.136.142:9001
    accessKey: admin
    secreKey: admin123456
    bucketName: sph

通过postman进行测试。

2.5 前端对接

修改sysUser.vue上传图片的页面代码,如下所示:

<el-upload
           class="avatar-uploader"
           action="http://localhost:8503/admin/system/fileUpload"
           :show-file-list="false"
           :on-success="handleAvatarSuccess"
           :headers="headers"
>
    
<script setup>
import { useApp } from '@/pinia/modules/app'

const headers = {
  token: useApp().authorization.token     // 从pinia中获取token,在进行文件上传的时候将token设置到请求头中
}

// 图像上传成功以后的事件处理函数
const handleAvatarSuccess = (response, uploadFile) => {
    sysUser.value.avatar = response.data
}

</script>

3 分配角色

3.1 需求分析

当用户点击"分配角色"按钮的时候,此时就会弹出一个对话框,在该对话框中会展示出来系统中所有的角色信息并且设置用户已有角色默认选中。用户此时就可以选择对应的角色,选择完毕以后,点击确定按钮,此时就需要请求后端接口,将选中的角色数据保存保存到sys_user_role表中。

效果图如下所示:

在这里插入图片描述

3.2 页面制作

具体代码如下所示:

<el-button type="warning" size="small" @click="showAssignRole(scope.row)">
    分配角色
</el-button>

<el-dialog v-model="dialogRoleVisible" title="分配角色" width="40%">
    <el-form label-width="80px">
        <el-form-item label="用户名">
            <el-input disabled :value="sysUser.userName"></el-input>
        </el-form-item>

        <el-form-item label="角色列表">
            <el-checkbox-group v-model="userRoleIds">
                <el-checkbox v-for="role in allRoles" :key="role.id" :checked="role.checked" :label="role.id">
                    {{ role.roleName }}
                </el-checkbox>
            </el-checkbox-group>
        </el-form-item>

        <el-form-item>
            <el-button type="primary">提交</el-button>
            <el-button @click="dialogRoleVisible = false">取消</el-button>
        </el-form-item>
    </el-form>
</el-dialog>

<script setup>
    
// 角色列表
const userRoleIds = ref([])
const allRoles = ref([
    {"id":1 , "roleName":"管理员","checked":true},
    {"id":2 , "roleName":"业务人员","checked":false},
    {"id":3 , "roleName":"商品录入员","checked":true},
])
const dialogRoleVisible = ref(false)
const showAssignRole = async row => {
  sysUser.value = row
  dialogRoleVisible.value = true
}

</script>

3.3 查询所有角色

首先需要将系统中所有的角色数据都查询出来,在前端给用户展示出来。

3.3.1 后端接口

SysRole

添加额外属性:是否已分配角色

private Boolean checked;
SysRoleController

表现层代码实现:

// com.atguigu.spzx.manager.controller.SysRoleController
@GetMapping(value = "/findAllRoles/{userId}")
public Result findAllRoles(@PathVariable("userId")Long userId) {
    List<SysRole> sysRoleList =  = sysRoleService.findAllRoles(userId);
    return Result.ok().data(sysRoleList);
}
SysRoleService

业务层代码实现:

// com.atguigu.spzx.manager.service.impl.SysRoleServiceImpl
@Override
public Map<String, Object> findAllRoles() {
   return sysRoleMapper.findSysRolesAndCheckedStatusByUserId(userId);
}
SysRoleMapper

持久层代码实现:

@Mapper
public interface SysRoleMapper {
    public abstract List<SysRole> findAllRoles();
}
SysRoleMapper.xml

在映射文件中添加sql语句:

<!-- 查询所有的角色数据 -->
<select id="findSysRolesAndCheckedStatusByUserId"
        resultType="com.atguigu.spzx.model.entity.system.SysRole">
    SELECT t1.* ,
    IF(t2.id IS NULL , FALSE , TRUE) 'checked'
    FROM sys_role t1
    LEFT JOIN sys_user_role t2
    ON t1.id = t2.role_id
    AND t2.user_id = #{userId}
    WHERE t1.is_deleted = 0
</select>

3.3.2 前端对接

sysRole.js

在src/api/sysRole.js文件中添加如下的请求方法:

// 查询所有的角色数据
export const GetAllRoleList = (userId) => {
    return request({
        url: `/admin/system/sysRole/findAllRoles/${userId}`,
        method: 'get'
    })
}
sysUser.vue

更改sysUser.vue的代码,添加查询所有角色数据的方法调用,如下所示:

<script setup>
import { GetAllRoleList } from '@/api/sysRole'; 

// 角色列表
const userRoleIds = ref([])
const allRoles = ref([
    {"id":1 , "roleName":"管理员"},
    {"id":2 , "roleName":"业务人员"},
    {"id":3 , "roleName":"商品录入员"},
])
const dialogRoleVisible = ref(false)
const showAssignRole = async row => {
  sysUser.value = row
  dialogRoleVisible.value = true

  // 查询所有的角色数据
  const {code , message , data } = await GetAllRoleList(row.id) ;
  allRoles.value = data

}
</script>

3.4 保存角色数据

3.4.1 后端接口

AssginRoleDto

创建一个实体类,封装请求参数,如下所示:

@Data
public class AssginRoleDto {

    private Long userId;				// 用户的id
    private List<Long> roleIdList;		// 角色id

}
SysRoleUser

创建一个与数据库表向对应的实体类,如下所示:

@Data
public class SysRoleUser extends BaseEntity {

    private Long roleId;       // 角色id
    private Long userId;       // 用户id

}
SysRoleUserController

表现层代码实现:

@RestController
@RequestMapping(value = "/admin/system/sysRoleUser")
public class SysRoleUserController {

    @Autowired
    private SysRoleUserService sysRoleUserService ;

    @PostMapping("/doAssign")
    public Result doAssign(@RequestBody AssginRoleDto assginRoleDto) {
        sysRoleUserService.doAssign(assginRoleDto) ;
        return Result.build(null , ResultCodeEnum.SUCCESS) ;
    }

}
SysRoleUserService

业务层代码实现:

@Service
public class SysRoleUserServiceImpl implements SysRoleUserService {

    @Autowired
    private SysRoleUserMapper sysRoleUserMapper ;

    @Transactional
    @Override
    public void doAssign(AssginRoleDto assginRoleDto) {

        // 删除之前的所有的用户所对应的角色数据
        sysRoleUserMapper.deleteByUserId(assginRoleDto.getUserId()) ;

        // 分配新的角色数据
        List<Long> roleIdList = assginRoleDto.getRoleIdList();
        if(roleIdList.size() > 0) {
            sysRoleUserMapper.doAssign(assginRoleDto) ;
        }

    }
    
}
SysRoleUserMapper

持久层代码实现:

@Mapper
public interface SysRoleUserMapper {

    public abstract void doAssign(AssginRoleDto assginRoleDto);		// 添加关联关系
    public abstract void deleteByUserId(Long userId);				// 根据用户的id删除数据

}
SysRoleUserMapper.xml

在SysRoleUserMapper.xml文件中添加sql语句

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.spzx.manager.mapper.SysRoleUserMapper">

    <delete id="deleteByUserId">
        delete from sys_user_role sur where sur.user_id = #{userId}
    </delete>

    <insert id="doAssign">
        insert into sys_user_role(user_id , role_id , create_time , update_time , is_deleted)
        values
        <foreach collection="roleIdList" separator="," item="roleId">
            ( #{userId} , #{roleId} , now() , now() , 0)
        </foreach>
    </insert>

</mapper>

3.4.2 前端对接

sysUser.js

在src/sysUser.js文件中添加如下请求接口方法:

// 给用户分配角色请求
export const DoAssignRoleToUser = (assginRoleVo) => {
    return request({
        url: "/admin/system/sysRoleUser/doAssign",
        method: 'post',
        data: assginRoleVo
    })
}
sysUser.vue

更改sysUser.vue的代码如下所示:

// 分配角色表单提交按钮添加doAssign事件处理函数
<el-button type="primary" @click="doAssign">提交</el-button>

<script setup>
import { DoAssignRoleToUser} from '@/api/sysUser'; 

// 角色分配按钮事件处理函数
const doAssign = async () => {
    let assginRoleVo = {
        userId: sysUser.value.id ,
        roleIdList: userRoleIds.value
    }
    const { code , message , data} = await DoAssignRoleToUser(assginRoleVo) ;
    if(code === 200) {
        ElMessage.success('操作成功')
        dialogRoleVisible.value = false 
        fetchData()
    }
}
</script>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.spzx.manager.mapper.SysRoleUserMapper">

    <delete id="deleteByUserId">
        delete from sys_user_role sur where sur.user_id = #{userId}
    </delete>

    <insert id="doAssign">
        insert into sys_user_role(user_id , role_id , create_time , update_time , is_deleted)
        values
        <foreach collection="roleIdList" separator="," item="roleId">
            ( #{userId} , #{roleId} , now() , now() , 0)
        </foreach>
    </insert>

</mapper>

3.4.2 前端对接

sysUser.js

在src/sysUser.js文件中添加如下请求接口方法:

// 给用户分配角色请求
export const DoAssignRoleToUser = (assginRoleVo) => {
    return request({
        url: "/admin/system/sysRoleUser/doAssign",
        method: 'post',
        data: assginRoleVo
    })
}
sysUser.vue

更改sysUser.vue的代码如下所示:

// 分配角色表单提交按钮添加doAssign事件处理函数
<el-button type="primary" @click="doAssign">提交</el-button>

<script setup>
import { DoAssignRoleToUser} from '@/api/sysUser'; 

// 角色分配按钮事件处理函数
const doAssign = async () => {
    let assginRoleVo = {
        userId: sysUser.value.id ,
        roleIdList: userRoleIds.value
    }
    const { code , message , data} = await DoAssignRoleToUser(assginRoleVo) ;
    if(code === 200) {
        ElMessage.success('操作成功')
        dialogRoleVisible.value = false 
        fetchData()
    }
}
</script>

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

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

相关文章

Kotlin:协程基础

点击查看&#xff1a;协程基础 中文文档 点击查看&#xff1a;协程基础 英文文档 第一个协程程序 import kotlinx.coroutines.*fun main(){GlobalScope.launch {delay(1000L)//delay 是一个特殊的 挂起函数 &#xff0c;它不会造成线程阻塞&#xff0c;但是会 挂起 协程&…

记一次dockerfile无法构建问题追溯

我有一个dockerfile如下&#xff1a; ENTRYPOINT ["/sbin/tini"&#xff0c;"-g", "--"] CMD /home/scrapy/start.sh 我原本的用意是先启动tini&#xff0c;再执行下面的cmd命令启动start.sh。 为啥要用tini&#xff1f; 因为我的这个docker…

springboot235基于SpringBoot的房屋交易平台的设计与实现

房屋交易平台设计与实现 摘 要 信息数据从传统到当代&#xff0c;是一直在变革当中&#xff0c;突如其来的互联网让传统的信息管理看到了革命性的曙光&#xff0c;因为传统信息管理从时效性&#xff0c;还是安全性&#xff0c;还是可操作性等各个方面来讲&#xff0c;遇到了互…

DDOS攻击处理方法

DDoS&#xff08;分布式拒绝服务&#xff09;攻击是一种网络攻击&#xff0c;攻击者通过发送大量的请求&#xff0c;超过目标服务器的处理能力&#xff0c;导致服务器服务不可用。本文将介绍如何处理DDoS攻击&#xff0c;并提供几种防范措施。 1. 认识DDoS攻击 DDoS攻击通常通过…

【Unity】使用Unity实现双屏显示

引言 在使用Unity的时候&#xff0c;有时候会需要使用双屏显示 简单来说就是需要在两个显示器中显示游戏画面 双屏显示注意点&#xff1a; ①双屏显示需要电脑有两个显示 ②双屏显示只能用于PC端 ③不仅仅可以双屏&#xff0c;Unity最大支持8屏显示 1.相机设置 ①我们打开Un…

【 VPX638】基于KU115 FPGA+C6678 DSP的6U VPX双FMC接口通用信号处理平台

板卡概述 VPX638是一款基于KU115 FPGA C6678 DSP的6U VPX双FMC接口通用信号处理平台&#xff0c;该平台采用一片Xilinx的Kintex UltraScale系列FPGA&#xff08;XCKU115&#xff09;作为主处理器&#xff0c;完成复杂的数据采集、回放以及数据预处理。采用1片TI的多核浮点运算…

三天学会阿里分布式事务框架Seata-nacos注册中心和配置中心支持

锋哥原创的分布式事务框架Seata视频教程&#xff1a; 实战阿里分布式事务框架Seata视频教程&#xff08;无废话&#xff0c;通俗易懂版&#xff09;_哔哩哔哩_bilibili实战阿里分布式事务框架Seata视频教程&#xff08;无废话&#xff0c;通俗易懂版&#xff09;共计10条视频&…

【C#】SixLabors.ImageSharp和System.Drawing两者知多少

欢迎来到《小5讲堂》 大家好&#xff0c;我是全栈小5。 这是《C#》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对知识点的理解和掌握。…

【南方CASS干货教程】几种CASS坐标批量提取的方法

【南方CASS干货教程】几种CASS坐标批量提取的方法 文章目录 前言方法一:指定点生成数据文件方法二:批量提取高程数据总结前言 一般在土方量计算中,需要提取区域的高程数据,CASS软件提供7种坐标文件提取,地形测绘、土方量计算、断面图绘制时都需要高程数据进行模型计算,提…

推特API(Twitter API)对接说明,用户code To Token换取

前期准备 提前准备、说明&#xff1a;目前对接推特api开发门户分为3个版本&#xff0c;分别是免费的&#xff0c;100美金一个月的基础版以及5000美金一个月的企业版&#xff0c;免费的目前就两个接口可以调用&#xff0c;所以想要对接和使用推特最基本的也需要付100美元一个月…

2024绿色能源、城市规划与环境国际会议(ICGESCE 2024)

2024绿色能源、城市规划与环境国际会议(ICGESCE 2024) 一、【会议简介】 随着全球气候变化和环境问题日益严重&#xff0c;绿色能源和可持续发展已成为全球关注的焦点。本次会议旨在汇聚全球在绿色能源、城市规划与环境领域的专家、学者和实践者&#xff0c;共同探讨和分享关于…

AutoGen Studio助力打造私人GPTs

微软最近在开源项目里的确挺能整活儿啊! 这次我介绍的是AutoGen Studio,我认为这个项目把AutoGen可用性又拔高了一个层次的项目 项目给自己的定义是交互式的多Agent workflow 项目地址:autogen/samples/apps/autogen-studio at main microsoft/autogen (github.com) 首先我…

【Leetcode每日一题】二分查找 - 山脉数组的峰顶索引(难度⭐⭐)(23)

1. 题目解析 Leetcode链接&#xff1a;852. 山脉数组的峰顶索引 这个问题的理解其实相当简单&#xff0c;只需看一下示例&#xff0c;基本就能明白其含义了。 核心在于找到题目中所说的峰值所在的下标并返回他们的下标即可。 2. 算法原理 峰顶及两侧数据特点分析 峰顶数据…

c语言经典测试题8

在c语言经典测试题6的第一题&#xff0c;大家是否想过可不可以将递归参数改为s呢&#xff1f;或许有的人已经试过了&#xff0c;但是发现好像不会有结果&#xff0c;其实是因为s为后置&#xff0c;先试用后加1&#xff0c;然而我们这个是在s出了函数之后才会运行加1操作&#x…

【Bugs】class path resource [xxx.xml] cannot be opened because it does not exist

报错&#xff1a; 关键报错信息&#xff1a; class path resource [scope.xml] cannot be opened because it does not exist完整报错信息&#xff1a; 2024-03-01 14:26:58 866 [main] DEBUG org.springframework.context.support.ClassPathXmlApplicationContext - Refres…

光谱下的养殖业:数据可视化的现代变革

在数字化时代&#xff0c;数据可视化在养殖业中崭露头角&#xff0c;为这一传统行业注入了新的活力。无论是家禽养殖还是水产养殖&#xff0c;数据可视化都以其直观、高效的特点&#xff0c;为养殖业带来了全新的发展机遇。下面我就以可视化从业者的角度&#xff0c;简单聊聊这…

【MATLAB源码-第152期】基于matlab的子空间方法(subspace method)的信道盲估计仿真,16QAM调制。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 基于子空间方法的信道盲估计是一种在通信领域中广泛使用的技术&#xff0c;用于在不直接知道发送信号的情况下估计通信信道的特性。这种方法的核心思想是通过接收到的信号来分析信号空间的结构&#xff0c;从而推断出信道的特…

设计师面试作品集注意!避免以下6个陷阱!

作品集是设计师提交简历和面试的关键。因此&#xff0c;与其担心自己学历低&#xff0c;不懂谈判技巧&#xff0c;不如多关注作品集。看了很多设计师的简历和作品集&#xff0c;发现下面的坑经常被踩。为了避免这些坑&#xff0c;建议您选择即时设计来制作作品集&#xff0c; …

C语言 vs Rust应该学习哪个?

C语言 vs Rust应该学习哪个&#xff1f; 在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「C语言的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&am…

阿里云降价,这泼天的富贵你接不接?附云服务器价格表

阿里云能处&#xff0c;关键时刻ta真降价啊&#xff01;2024新年伊始阿里云带头降价了&#xff0c;不只是云服务器&#xff0c;云数据库和存储产品都降价&#xff0c;阿里云新老用户均可购买99元服务器、199元服务器&#xff0c;续费不涨价&#xff0c;阿里云百科aliyunbaike.c…