ASP.NET Core列表增删改查

前置要求:

1. vue+element-plus实现前端静态页面

HelloWorld.vue

<template>
  <h2>hello界面</h2>
  <div class="tableList">

   <!-- 搜索框 -->
   <el-row :gutter="20">
      <el-col :span="8">
        <!-- 搜索与添加区域 -->
          <el-input placeholder="请输入内容"
          v-model="SearchVal" clearable @clear="getUserList" @keyup.enter="enterSearch">
          <template #append>
           <el-button @click="getUserList"><el-icon><search /></el-icon></el-button>
          </template>
          </el-input>
      </el-col>
      <el-col :span="2">
        <el-button type="primary" @click="openAdd">add</el-button>
      </el-col>
      <el-col :span="4">
        <el-button type="danger" @click="onDel">delete</el-button>
      </el-col>
    </el-row>

    <!-- 表单 -->
    <el-table :data="tableData" style="width: 100%">
      <el-table-column type="selection" width="55" />
    <el-table-column prop="date" label="Date" width="180" />
    <el-table-column prop="name" label="Name" width="100" />
    <el-table-column prop="oder" label="Oder" width="100" />
    <el-table-column prop="address" label="Address" />
    <!-- 操作按钮 -->
    <el-table-column label="Operations">
      <template #default="scope">
        <el-button size="small" @click="handleEdit(scope.$index, scope.row)"
          >Edit</el-button
        >
        <el-button
          size="small"
          type="danger"
          @click="handleDelete(scope.$index, scope.row)"
          >Delete</el-button
        >
      </template>
    </el-table-column>
  </el-table>
  <el-pagination background layout="prev, pager, next" :total="total"  @current-change="handleCurrentChange"/>
  </div>
</template>

<script lang="ts" setup >
import { ref } from "vue";
const SearchVal=ref("")
const total=ref(100)
const enterSearch=()=>{}
const openAdd=()=>{}
const onDel=()=>{}

const handleEdit = (index: number, row: User) => {
  console.log(index, row)
}
const handleDelete = (index: number, row: User) => {
  console.log(index, row)
}

const handleCurrentChange = (val: number) => {
  console.log(val)
}

const tableData = [
  {
    date: '2016-05-03',
    name: 'Tom',
    oder:1,
    address: 'No. 189, Grove St, Los Angeles',
  },
  {
    date: '2016-05-02',
    name: 'Tom',
    oder:2,
    address: 'No. 189, Grove St, Los Angeles',
  },
  {
    date: '2016-05-04',
    name: 'Tom',
    oder:3,
    address: 'No. 189, Grove St, Los Angeles',
  },
  {
    date: '2016-05-01',
    name: 'Tom',
    oder:4,
    address: 'No. 189, Grove St, Los Angeles',
  },
]
</script>

<style lang="scss" scoped >
.tableList{
 margin:  0 500px;
}
.el-pagination{
  margin-top: 20px;
}
</style>

1.2 创建弹框组件app.vue

<!-- 弹窗组件 -->
<template>
  <el-dialog v-model="dialogFormVisible" title="新增" with="30%">
    <el-form :model="form">
      <el-form-item label="时间" prop="date">
        <el-input v-model="form.data" type="date" placeholder="请选择一个时间" :disabledDate="disabledDate"/>
      </el-form-item>
      <el-form-item label="名称" prop="name">
        <el-input v-model="form.name"></el-input>
      </el-form-item>
      <el-form-item label="地址" prop="address">
        <el-input v-model="form.address"/>
      </el-form-item>
      <el-form-item label="排序" prop="order">
        <el-input v-model="form.oder"/>
      </el-form-item>
    </el-form>
    <template #footer>
      <span class="dialog-footer">
        <el-button @click="dialogFormVisible = false">Cancel</el-button>
        <el-button type="primary" @click="dialogFormVisible = false">
          Confirm
        </el-button>
      </span>
    </template>
  </el-dialog>
</template>
<script setup lang="ts">
import {ref} from "vue"

const dialogFormVisible=ref(false)
const form=ref()
const disabledDate=(time:any)=>{//最大时间从今天开始
    const _maxTime=Date.now()-24*60*60*1000*1
    return time.getTime()<=_maxTime
}


</script>

<style scoped lang="scss">
.dialog-footer button:first-child {
  margin-right: 10px;
}
.el-button--text {
  margin-right: 15px;
}
.el-select {
  width: 300px;
}
.el-input {
  width: 300px;
}
.dialog-footer button:first-child {
  margin-right: 10px;
}
</style>

完善方法组件的代码:组件的引用,组件的传值prop,计算属性,事件监听、子触发父组件的事件

HelloWorld.vue

<template>
  <h2>hello界面</h2>
  <div class="tableList">

   <!-- 搜索框 -->
   <el-row :gutter="20">
      <el-col :span="8">
        <!-- 搜索与添加区域 -->
          <el-input placeholder="请输入内容"
          v-model="SearchVal" clearable @clear="getUserList" @keyup.enter="enterSearch">
          <template #append>
           <el-button @click="getUserList"><el-icon><search /></el-icon></el-button>
          </template>
          </el-input>
      </el-col>
      <el-col :span="2">
        <el-button type="primary" @click="openAdd">add</el-button>
      </el-col>
      <el-col :span="4">
        <el-button type="danger" @click="onDel">delete</el-button>
      </el-col>
    </el-row>

    <!-- 表单 -->
    <el-table :data="tableData" style="width: 100%">
      <el-table-column type="selection" width="55" />
    <el-table-column prop="date" label="Date" width="180" />
    <el-table-column prop="name" label="Name" width="100" />
    <el-table-column prop="order" label="Order" width="100" />
    <el-table-column prop="address" label="Address" />
    <!-- 操作按钮 -->
    <el-table-column label="Operations">
      <template #default="scope">
        <el-button size="small" @click="handleEdit(scope.$index, scope.row)"
          >Edit</el-button
        >
        <el-button
          size="small"
          type="danger"
          @click="handleDelete(scope.$index, scope.row)"
          >Delete</el-button
        >
      </template>
    </el-table-column>
  </el-table>
  <el-pagination background layout="prev, pager, next" :total="total"  @current-change="handleCurrentChange"/>
  </div>
  <addVue :isShow="isShow" :info="info" @closeAdd="closeAdd" @success="success"></addVue>
</template>

<script lang="ts" setup >
import { ref } from "vue";
import User from "../class/User.ts"
import addVue from "../components/add.vue"
const SearchVal=ref("")
const total=ref(100)

const isShow=ref(false)
//定义info
const info=ref<User>(new User())

const enterSearch=()=>{}
const openAdd=()=>{
  isShow.value=true
}
const onDel=()=>{}

const handleEdit = (index: number, row: User) => {
  console.log(index, row)
  info.value=row
  isShow.value=true
}
const handleDelete = (index: number, row: User) => {
  console.log(index, row)
}

const handleCurrentChange = (val: number) => {
  console.log(val)
}
const closeAdd=()=>{
  isShow.value=false
  info.value=new User()
}
const success=()=>{
  isShow.value=false
  info.value=new User()
  EIMessage.success(message)
}



const tableData = [
  {
    date: '2016-05-03',
    name: 'Tom',
    order:1,
    address: 'No. 189, Grove St, Los Angeles',
  },
  {
    date: '2016-05-02',
    name: 'Tom',
    order:2,
    address: 'No. 189, Grove St, Los Angeles',
  },
  {
    date: '2016-05-04',
    name: 'Tom',
    order:3,
    address: 'No. 189, Grove St, Los Angeles',
  },
  {
    date: '2016-05-01',
    name: 'Tom',
    order:4,
    address: 'No. 189, Grove St, Los Angeles',
  },
]
</script>

<style lang="scss" scoped >
.tableList{
 margin:  0 500px;
}
.el-pagination{
  margin-top: 20px;
}
</style>

app.vue

作用:利用三元表达式,使用同一个组件展示不同的弹框内容

<!-- 弹窗组件 -->
<template>
  <el-dialog v-model="dialogFormVisible" :title="info?.name?'修改':'新增'" with="30%" @close="$emit('closeAdd')" draggable="true">
    <!-- 使用三元表达式控制标题展示 -->
    <el-form :model="form">
      <el-form-item label="时间" prop="date">
        <el-input v-model="form.date" type="date" placeholder="请选择一个时间" :disabledDate="disabledDate"/>
      </el-form-item>
      <el-form-item label="名称" prop="name">
        <el-input v-model="form.name"></el-input>
      </el-form-item>
      <el-form-item label="地址" prop="address">
        <el-input v-model="form.address"/>
      </el-form-item>
      <el-form-item label="排序" prop="order">
        <el-input v-model="form.order"/>
      </el-form-item>
    </el-form>
    <template #footer>
      <span class="dialog-footer">
        <el-button @click="closeAdd()">取消</el-button>
        <el-button type="primary" @click="save()">
          确认
        </el-button>
      </span>
    </template>
  </el-dialog>
</template>
<script setup lang="ts">
import {ref,Ref,computed,watch} from "vue"
import User from "../class/User"
const prop=defineProps({//内置的传参工具  接收使用prop传递过来的数据
    isShow:Boolean,//对于接收的类型进行控制
    info:User
})


const disabledDate=(time:any)=>{//最大时间从今天开始
    const _maxTime=Date.now()-24*60*60*1000*1
    return time.getTime()<=_maxTime
}
const dialogFormVisible=computed(()=>prop.isShow)//表单的展示与隐藏绑定在isShow上
const form:Ref<User>=ref<User>({//声明使用User类
    id:"",
    date:"",
    name:"",
    address:"",
    order:0
})
watch(()=>prop.info,(newInfo)=>{
    if(newInfo){
        form.value={
            id:newInfo.id,
            date:newInfo.date,
            name:newInfo.name,
            address:newInfo.address,
            order:newInfo.order 
        }
    }
})
const emits=defineEmits(["closeAdd","success"])
const closeAdd=()=>{
   emits("closeAdd")
}
const save=()=>{
    emits("success")
}

</script>

<style scoped lang="scss">
.dialog-footer button:first-child {
  margin-right: 10px;
}
.el-button--text {
  margin-right: 15px;
}
.el-select {
  width: 300px;
}
.el-input {
  width: 300px;
}
.dialog-footer button:first-child {
  margin-right: 10px;
}
</style>

2、后端接口的创建与开发

安装nuget:sqlSugarCore

Program.cs

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.MapGet("/test", () =>//方法("/路径",()=>{})
{
    return "ok";
});


app.Run();

创建Model->User.cs

using SqlSugar;

namespace WebApplication1.Model
{
    public class User
    {
        [SugarColumn(IsPrimaryKey = true)]//使用sqlSugar:配置主键
        public int Id { get; set; }
        public string Name { get; set; }
        public DateTime Date { get; set; }
        public string Address { get; set; }
        public int Order { get; set; }

    }
}

创建Data->SqlSugarHelper.cs

using SqlSugar;

namespace WebApplication1.Data
{
    public class SqlSugarHelper
    {
        public static SqlSugarScope Db = new SqlSugarScope(new ConnectionConfig() 
        {
            ConnectionString= "Data Source=.;Initial Catalog=BookMS;Persist Security Info=True;User ID=sa;Password=123456;Trust Server Certificate=True",
            DbType=DbType.SqlServer,//数据库类型
            IsAutoCloseConnection=true,//不手动colse 自动关闭连接
        },
            db =>
            {
                db.Aop.OnLogExecuting = (sql, pars) =>
                {
                    Console.WriteLine(sql);//输出sql返回的数据,不影响性能开发阶段可以使用
                };
            }
        );
    }
}

完善SqlSugarHelper.cs实现增删改查数据库的执行语句

using SqlSugar;
using System.Reflection;
using WebApplication1.Model;

namespace WebApplication1.Data
{
    public class SqlSugarHelper
    {
        public static SqlSugarScope Db = new SqlSugarScope(new ConnectionConfig() 
        {
            ConnectionString= "Data Source=.;Initial Catalog=BookMS;Persist Security Info=True;User ID=sa;Password=123456;Trust Server Certificate=True",
            DbType=DbType.SqlServer,//数据库类型
            IsAutoCloseConnection=true,//不手动colse 自动关闭连接
        },
            db =>
            {
                db.Aop.OnLogExecuting = (sql, pars) =>
                {
                    Console.WriteLine(sql);//输出sql返回的数据,不影响性能开发阶段可以使用
                };
            });

        /// <summary>
        /// 初始化数据库
        /// </summary>
        /// <returns></returns>
        public static string InitDateBase()//自动创建表使用sqlSuger的配置
        {
            try
            {
                //创建数据库
                Db.DbMaintenance.CreateDatabase();
                //创建表
                string nspace = "WebApplication1.Model";
                Type[] ass=Assembly.LoadFrom(AppContext.BaseDirectory+ "WebApplication1.dll").GetTypes().Where(p=>p.Namespace == nspace).ToArray();
                Db.CodeFirst.SetStringDefaultLength(200).InitTables(ass);
                //初始化数据
                Db.Deleteable<User>().ExecuteCommand();//清空数据
                List<User> list = new List<User>();
                for(int i = 1; i <= 5; i++)
                {
                    list.Add(new User()
                    {
                        Id = Guid.NewGuid().ToString(),
                        Name="Tom"+i,
                        Date=DateTime.Now,
                        Address="北京路138号",
                        Order=i,
                    });
                }
                for (int i = 6; i <= 10; i++)
                {
                    list.Add(new User()
                    {
                        Id = Guid.NewGuid().ToString(),
                        Name = "Tom" + i,
                        Date = DateTime.Now,
                        Address = "北京路138号",
                        Order = i,
                    });
                }
                for (int i = 11; i <= 30; i++)
                {
                    list.Add(new User()
                    {
                        Id = Guid.NewGuid().ToString(),
                        Name = "Tom" + i,
                        Date = DateTime.Now,
                        Address = "北京路138号",
                        Order = i,
                    });
                }
                Db.Insertable(list).ExecuteCommand();
                return "ok";
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }

        ///<summary>
        ///1.读取用户列表
        ///</summary>
        public static Result GetUsers(Model req)
        {
            Result result = new Result();
            int total = 0;
            result.Res = Db.Queryable<User>()
                .WhereIF(!string.IsNullOrEmpty(req.KeyWord), s => s.Name.Contains(req.KeyWord) || s.Address.Contains(req.KeyWord))//过滤数据
                .OrderBy(s => s.Order)//排序
                .ToOffsetPage(req.PageIndex, req.PageSize, ref total);//分页
            result.Total = total;
            return result;
        }
        ///<summary>
        ///2.新增
        ///</summary>
        public static bool Add(AddReq req)
        {
            User info =new User()
            {
                Id=Guid.NewGuid().ToString(),
                Name = req.Name,
                Date=req.Date,
                Address=req.Address,
                Order=req.Order
            };
            if (Db.Queryable<User>().Any(p => p.Name == req.Name))
            {
                return false;
            }
            return Db.Insertable(info).ExecuteCommand()>0;
        }
        ///<summary>
        ///3.编辑
        ///</summary>
        public static bool Edit(User req)
        {
            User info =Db.Queryable<User>().First(p=>p.Id==req.Id);
            if (info == null)
            {
                return false;
            }
            info.Name = req.Name;
            info.Date = req.Date;
            info.Address = req.Address;
            info.Order = req.Order;
            return Db.Updateable(info).ExecuteCommand() > 0;//差不多是返回影响行数的意思
            
        }
        ///<summary>
        ///4.删除方法(单个及批量都可以)
        ///</summary>
        public static bool Del(string ids)
        {
            return Db.Ado.ExecuteCommand($"DELETE [User] WHERE Id IN({ids})")>0;
        }
    }

    public class Model//分页
    {
        public string KeyWord { get; set; }
        public int PageIndex { get; set; }
        public int PageSize { get; set; }
        public int Total {  get; set; }
    }
    public class Result//结果
    {
        public int Total { get; set; }
        public object Res { get; set; }
    }
    public class AddReq//添加的请求参数
    {
        //public string Id { get; set; }
        public string Name { get; set; }
        public DateTime Date { get; set; }
        public string Address { get; set; }
        public int Order { get; set; }
    }
}

在Program.cs网络请求中追加代码

app.MapGet("/codefrist", () =>
{
    return SqlSugarHelper.InitDateBase();
});
app.MapPost("/list", (Model req) =>
{
    return SqlSugarHelper.GetUsers(req);
});
app.MapPost("/add", (AddReq req) =>
{
    return SqlSugarHelper.Add(req);
});
app.MapPost("/edit", (User req) =>
{
    return SqlSugarHelper.Edit(req);
});
app.MapDelete("/delete", (string ids) => 
{
    return SqlSugarHelper.Del(ids);
});

实现对数据库的增删改查

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Angular系列教程之DOM操作

文章目录 引言1. ElementRef2. Renderer23. ViewChild结论 引言 在Angular中&#xff0c;DOM操作是开发Web应用程序的一个重要方面。通过对DOM进行操作&#xff0c;我们可以动态地修改页面内容、样式和元素行为。本文将详细介绍如何在Angular中进行DOM操作&#xff0c;并提供相…

LTC6820和isoSPI使用

1、MSTR主控/受控 MSTR (引脚 11/ 引脚 12)&#xff1a;串行接口主 / 从选择器输入。MSTR接VCC&#xff0c;则LTC6820为从机&#xff1b;MSTR接GND&#xff0c;则LTC6820为主机 2、SLOW慢速/快速 SLOW (引脚 12/ 引脚 13)&#xff1a;慢速接口选择输入。当时钟频率≤ 200kHz …

Top6 最好的 Android 数据恢复软件免费获取

虽然在智能手机上随身携带您最喜爱的音乐收藏或珍贵的录音很方便&#xff0c;但如果您的设备出现技术问题或您不小心删除了文件&#xff0c;文件也有可能丢失。 不管文件是如何删除或丢失的&#xff0c;丢失那些珍贵的音频文件的痛苦对每个人来说都是一样的。这就是我们创建本…

php反序列化之pop链构造

常见魔术方法的触发 __construct() //创建类对象时调用 __destruct() //对象被销毁时触发 __call() //在对象中调用不可访问的方法时触发 __callStatic() //在静态方式中调用不可访问的方法时触发 __get() //调用类中不存在变量时触发&#xff08;找有连续箭头的…

5 个被低估的开源项目

文章目录 1.集算器 -数据处理2. Firecamp - 邮递员替代方案3.Keploy——后端 测试4. Hanko - 密钥验证5. Zrok - Ngrok 类固醇 长话短说 本文列出了五个不太受欢迎的优秀项目&#xff0c;您应该尝试一下。&#x1f525; 这些工具旨在改进数据处理、API 开发、后端测试、身份验…

【无标题】【第6次修改了可删除可持久保存的前端html备忘录:去掉第2页面可误删除

第6次修改了可删除可持久保存的前端html备忘录:去掉第2页面 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0">&l…

微信小程序防止截屏录屏

一、使用css添加水印 使用微信小程序原生的view和css给屏幕添加水印这样可以防止用户将小程序内的隐私数据进行截图或者录屏分享导致信息泄露&#xff0c;给小程序添加一个水印浮层。这样即使被截图或者拍照&#xff0c;也能轻松地确定泄露的源头。效果图如下&#xff1a; 代码…

zookeeper简介

Zookeeper 是一个开源的分布式的&#xff0c;为分布式框架提供协调服务的 Apache 项目。 Zookeeper工作机制 Zookeeper从设计模式角度来理解&#xff1a;是一个基于观察者模式设计的分布式服务管理框架&#xff0c;它负责存储和管理大家都关心的数据&#xff0c;然后接受观察者…

安全狗方案入选工信部《2023年工业和信息化领域数据安全典型案例名单》

近日&#xff0c;工业和信息化部网络安全管理局公布了2023年工业和信息化领域数据安全典型案例名单。 安全狗与厦门卫星定位应用股份有限公司、中移 (上海) 信息通信科技有限公司联合申报的智慧交通云数据安全与隐私保障典型案例也成功入选。 厦门服云信息科技有限公司&#…

Rust-数组

数组是一个容器&#xff0c;它在一块连续空间内存中&#xff0c;存储了一系列的同样类型的数据。 数组中元素的占用空间大小必须是编译期确定的。 数组本身所容纳的元素个数也必须是编译期确定的&#xff0c;执行阶段不可变。 如果需要使用变长的容器&#xff0c;可以使用标…

vue2使用electron以及打包配置

1.创建项目 vue create vue-project 2.安装electron vue add electron-builder会自动安装相关依赖 安装成功后会在src下自动生成一个background.js文件就是相应的electron的配置信息 use strictimport { app, protocol, BrowserWindow } from electron import { createProto…

缓存和数据库一致性

前言&#xff1a; 项目的难点是如何保证缓存和数据库的一致性。无论我们是先更新数据库&#xff0c;后更新缓存还是先更新数据库&#xff0c;然后删除缓存&#xff0c;在并发场景之下&#xff0c;仍然会存在数据不一致的情况&#xff08;也存在删除失败的情况&#xff0c;删除…

Docker-Compose构建lnmp

目录 实验前准备安装composeNginx准备工作目录准备Dockerfile脚本准备nginx.conf Mysql准备工作目录编写Dockerfile脚本准备my.cnf PHP准备工作目录准备相关文件 编写docker-compose.yml配置文件目录结构启动测试Mysql授权测试 问题Mysql容器无权访问问题浏览器访问file not fo…

计算机网络 网络安全

网络安全 网络安全问题概述 计算机网络面临的女全性威胁 计算机网络的通信而临两大类威胁&#xff0c;即被动攻击和主动攻击 被动攻击是指攻击者从网络上窃听他人的通信内容。通常把这类攻击称为截获。在被动攻击中&#xff0c;攻击者只是观察和分析某一个协议数据单元 PDU…

R语言【paleobioDB】——pbdb_orig_ext():绘制随着时间变化而出现的新类群

Package paleobioDB version 0.7.0 paleobioDB 包在2020年已经停止更新&#xff0c;该包依赖PBDB v1 API。 可以选择在Index of /src/contrib/Archive/paleobioDB (r-project.org)下载安装包后&#xff0c;执行本地安装。 Usage pbdb_orig_ext (data, rank, temporal_extent…

各种版本对应关系:SpringCloudAlibaba——SpringCloud——SpringBoot——SpringFramework——JDK

SpringCloudAlibaba——SpringCloud——SpringBoot——SpringFramework——JDK 一般情况&#xff0c;在https://github.com/项目/wiki目录下有发布信息及对应的要求其他依赖的版本信息SpringCloudAlibaba——SpringCloud——SpringBootSpringBoot和SpringFramework的版本对应关…

基于MATLAB计算无线通信覆盖(一)环境准备

一、环境 MATLAB 2022b 注&#xff1a;开始仿真前需部署地理坐标区和地理图&#xff0c;最好采用第三种&#xff0c;直接把底图数据下载到本地&#xff0c;防止连接不上网络时只能显示darkwater的底图。 可用于地理坐标区和地理图的底图如下表所示 二、下载底图并安装 工具&…

如何用GPT进行论文润色与改写?

详情点击链接&#xff1a;如何用GPT/GPT4进行论文润色与改写&#xff1f;一OpenAI 1.最新大模型GPT-4 Turbo 2.最新发布的高级数据分析&#xff0c;AI画图&#xff0c;图像识别&#xff0c;文档API 3.GPT Store 4.从0到1创建自己的GPT应用 5. 模型Gemini以及大模型Claude2二…

最新可用GPT-3.5、GPT-4、Midjourney绘画、DALL-E3文生图模型教程【宝藏级收藏】

一、前言 ChatGPT3.5、GPT4.0、GPT语音对话、Midjourney绘画&#xff0c;文档对话总结DALL-E3文生图&#xff0c;相信对大家应该不感到陌生吧&#xff1f;简单来说&#xff0c;GPT-4技术比之前的GPT-3.5相对来说更加智能&#xff0c;会根据用户的要求生成多种内容甚至也可以和…

极狐GitLab 线下『 DevOps专家训练营』成都站开班在即

成都机器人创新中心联合极狐(GitLab)隆重推出极狐GitLab DevOps系列认证培训课程。该课程主要面向使用极狐GitLab的DevOps工程师、安全审计人员、系统运维工程师、系统管理员、项目经理或项目管理人员&#xff0c;完成该课程后&#xff0c;学员将达到DevOps的专家级水平&#x…