0


Vue3前端 .NET 后端接口【前后端分离】

Vue3前端 .NET 后端接口【前后端分离】 觉得不错就点个赞吧

文章目录

1.前端创建Vue3项目👷

1.Win+R cmd Enter 选择一个创建一个存放项目的文件夹使用npm命令创建项目进行配置

npm create vue@latest

2.项目依赖:

Vue3+Vite+TypeScript+JSX+Vue-Router+Pinia+Vitest+Cypress+Eslint+Prettier+Vue DevTools

3.命令如图依次执行

在这里插入图片描述

完成时窗口显示 看见成功的显示心情也很愉快把!😀😀😀

在这里插入图片描述

引入[Element-plus](快速开始 | Element Plus (element-plus.org)) 前端框架

npm install element-puls
//在main.ts中import Element from'element-plus'import'element-plus/dist/index.css'
app.use(Element)

删除App.Vue 前端HTML页面代码 打开[Element-plus](快速开始 | Element Plus (element-plus.org)) 使用组件查看页面效果

<template>
  <el-form
    ref="ruleFormRef"
    style="max-width: 600px"
    :model="ruleForm"
    status-icon
    :rules="rules"
    label-width="auto"
    class="demo-ruleForm"
  >
    <el-form-item label="Password" prop="pass">
      <el-input v-model="ruleForm.pass" type="password" autocomplete="off" />
    </el-form-item>
    <el-form-item label="Confirm" prop="checkPass">
      <el-input v-model="ruleForm.checkPass" type="password" autocomplete="off" />
    </el-form-item>
    <el-form-item label="Age" prop="age">
      <el-input v-model.number="ruleForm.age" />
    </el-form-item>
    <el-form-item>
      <el-button type="primary" @click="submitForm(ruleFormRef)">Submit</el-button>
      <el-button @click="resetForm(ruleFormRef)">Reset</el-button>
    </el-form-item>
  </el-form>
</template>

<script lang="ts" setup>
import { reactive, ref } from 'vue'
import type { FormInstance, FormRules } from 'element-plus'

const ruleFormRef = ref<FormInstance>()

const checkAge = (rule: any, value: any, callback: any) => {
  if (!value) {
    return callback(new Error('Please input the age'))
  }
  setTimeout(() => {
    if (!Number.isInteger(value)) {
      callback(new Error('Please input digits'))
    } else {
      if (value < 18) {
        callback(new Error('Age must be greater than 18'))
      } else {
        callback()
      }
    }
  }, 1000)
}

const validatePass = (rule: any, value: any, callback: any) => {
  if (value === '') {
    callback(new Error('Please input the password'))
  } else {
    if (ruleForm.checkPass !== '') {
      if (!ruleFormRef.value) return
      ruleFormRef.value.validateField('checkPass', () => null)
    }
    callback()
  }
}
const validatePass2 = (rule: any, value: any, callback: any) => {
  if (value === '') {
    callback(new Error('Please input the password again'))
  } else if (value !== ruleForm.pass) {
    callback(new Error("Two inputs don't match!"))
  } else {
    callback()
  }
}

const ruleForm = reactive({
  pass: '',
  checkPass: '',
  age: ''
})

const rules = reactive<FormRules<typeof ruleForm>>({
  pass: [{ validator: validatePass, trigger: 'blur' }],
  checkPass: [{ validator: validatePass2, trigger: 'blur' }],
  age: [{ validator: checkAge, trigger: 'blur' }]
})

const submitForm = (formEl: FormInstance | undefined) => {
  if (!formEl) return
  formEl.validate((valid) => {
    if (valid) {
      console.log('submit!')
    } else {
      console.log('error submit!')
      return false
    }
  })
}

const resetForm = (formEl: FormInstance | undefined) => {
  if (!formEl) return
  formEl.resetFields()
}
</script>

<style scoped>
header {
  line-height: 1.5;
  max-height: 100vh;
}

.logo {
  display: block;
  margin: 0 auto 2rem;
}

nav {
  width: 100%;
  font-size: 12px;
  text-align: center;
  margin-top: 2rem;
}

nav a.router-link-exact-active {
  color: var(--color-text);
}

nav a.router-link-exact-active:hover {
  background-color: transparent;
}

nav a {
  display: inline-block;
  padding: 0 1rem;
  border-left: 1px solid var(--color-border);
}

nav a:first-of-type {
  border: 0;
}

@media (min-width: 1024px) {
  header {
    display: flex;
    place-items: center;
    padding-right: calc(var(--section-gap) / 2);
  }

  .logo {
    margin: 0 2rem 0 0;
  }

  header .wrapper {
    display: flex;
    place-items: flex-start;
    flex-wrap: wrap;
  }

  nav {
    text-align: left;
    margin-left: -1rem;
    font-size: 1rem;

    padding: 1rem 0;
    margin-top: 1rem;
  }
}
</style>

ok👌**我们可以配置自己的模板用于生成Vue基础代码 ** 设置 ->使用代码片段->创建自己的代码配置文件粘贴代码

{"vue-template3":{"prefix":"vue3","body":[// "<!--",// "  *@author [前端_XXX]", // 作者名称// "  *@date $CURRENT_YEAR/$CURRENT_MONTH/$CURRENT_DATE $CURRENT_HOUR:$CURRENT_MINUTE:$CURRENT_SECOND",//当前时间// "!-->","<template>","  <div>","","  </div>","</template>","<script>","import {ref, reactive, defineComponent, Ref, onMounted} from 'vue';","export default defineComponent({","     name:'',","     setup(){","     onMounted(() => {","","     });","     return{","","     };","     }"," })","</script>","<style scoped>","","</style>"],"description":"vue-template3"},"vue-templateSetup3":{"prefix":"setup","body":["<!-- eslint-disable vue/multi-word-component-names =","  *@author [前端_XXX]",// 作者名称"  *@date $CURRENT_YEAR/$CURRENT_MONTH/$CURRENT_DATE $CURRENT_HOUR:$CURRENT_MINUTE:$CURRENT_SECOND",//当前时间"!-->","<template>","  <div></div>","</template>","<script setup lang='ts'>","import { onMounted } from 'vue';","onMounted(() => { });","</script>","<style scoped></style>"],"description":"vue-template3"},"vue-template2":{"prefix":"vue2","body":[// "<!--",// "  *@author [前端_XXX]", // 作者名称// "  *@date $CURRENT_YEAR/$CURRENT_MONTH/$CURRENT_DATE $CURRENT_HOUR:$CURRENT_MINUTE:$CURRENT_SECOND",//当前时间// "!-->","<template>","  <div>","","  </div>","</template>","<script>","export default {","  data () {","    return {","","    }","  }","}","</script>","<style lang=\"scss\" scoped>","","</style>"],"description":"vue-template2"},}

使用setup+tab tab生成语法糖模板

<!-- eslint-disable vue/multi-word-component-names =
  *@author [前端_XXX]
  *@date 2024/04/06 19:41:20
!-->
<template>
  <div></div>
</template>
<script setup lang="ts">
import { onMounted } from 'vue'
onMounted(() => {})
</script>
<style scoped></style>

配置.eslintrc.cjs代码检查规则,避免代码爆红

 rules:{// 去掉函数()前面的空格'space-before-function-paren':'off','no-console': process.env.NODE_ENV==='production'?'warn':'off','no-debugger': process.env.NODE_ENV==='production'?'warn':'off',// 关闭驼峰命名规则'vue/multi-word-component-names':0}

2.后端.NET 创建ASP.NET Core WebApi项目👷

Win+r cmd Enter 选择一个工作磁盘

mkdir Api
------------
cd Api
------------
dotnet new webapi -n Api   //Api是项目名
------------
cd Api
------------
dotnet run 

在这里插入图片描述

下图为Vistual Studio创建好的Api项目,注意作者这里没有取消勾选https的 不使用https 请注释掉此行****注意dotnet版本为.NET8

在这里插入图片描述

在这里插入图片描述

访问你的项目地址 http://loaclhost端口号/swaager+Enter

在这里插入图片描述

**在文件夹下新建解决方案文件 **

dotnet new sln -n 解决方案名称

将创建的项目加入到该解决方案当中

dotnet sln add 项目文件夹路径

3.MySql 数据库创建库与表

ok👌 下面打开MySql服务 创建数据库连接数据库

Win+R cmd Enter
--------------
net start mysql80  mysql80 为mysql服务名
-------------
mysql -u 用户名 -p
-------------
下图为登录成功

在这里插入图片描述

打开可视化工具 作者使用 DataGrip 进行创建表进行测试 数据库自行创建 可以手动或者代码形式

DataGrip2022破解

//创建表代码use test_db;createtable  T_user(
    t_Id VARCHAR(50)notnullprimarykeyCOMMENT'用户id',
    t_Act VARCHAR(50)NOTNULLCOMMENT'用户账户',
    t_Pwd VARCHAR(50)NOTNULLCOMMENT'用户密码',
    t_IsDel smallintNOTNULLCOMMENT'是否删除',
    t_State smallintNOTNULLCOMMENT'用户状态',
    t_Code VARCHAR(50)NOTNULLCOMMENT'登录凭证',
    t_CeTime DatetimeNOTNULLCOMMENT'创建时间',
    t_Uptime DatetimeNOTNULLCOMMENT'修改时间');createtable  T_user_info(
    t_Id VARCHAR(50)notnullprimarykeyCOMMENT'用户信息id',
    t_Uid VARCHAR(50)notnullCOMMENT'用户id,外键',
    t_Name VARCHAR(50)NOTNULLCOMMENT'用户名',
    t_Nick VARCHAR(50)NOTNULLCOMMENT'昵称',
    t_Sex VARCHAR(50)NOTNULLCOMMENT'性别',
    t_Age VARCHAR(50)NOTNULLCOMMENT'年龄',
    t_Phone VARCHAR(50)NOTNULLCOMMENT'电话',
    t_Address VARCHAR(50)NOTNULLCOMMENT'地址',
    t_Email smallintNOTNULLCOMMENT'邮箱',
    t_Birth smallintNOTNULLCOMMENT'生日',
    t_Card VARCHAR(50)NOTNULLCOMMENT'身份',
    t_CeTime DatetimeNOTNULLCOMMENT'创建时间',
    t_Uptime DatetimeNOTNULLCOMMENT'修改时间',FOREIGNKEY(t_Uid)references T_user(t_Id))

下图为DataGrip 连接MySql 新建查询窗口 创建表代码图片

在这里插入图片描述

ok👌 下面咱们可以新建后台项目层级结构 编写底层创建接口,配置数据库连接,进行接口测试了

**搭建后端ASP.NET Core WebApi项目架构 **

cmd 命令

F: 跳转到磁盘
cd /work   目录
mkdir TApi  创建存放项目目录  
dotnet new sln -n TApi 创建TApi解决方案
mkdir {Web,Data,Model,Common,Services,IServices,Business,IBusiness} 创建多个同级目录
在各级目录下创建对应项目
dotnet new classlib -n UI -o F:/work/TApi/Web/ 
dotnet new classlib -n DB -o F:/work/TApi/Data/ 
dotnet new classlib -n Entity -oF:/work/TApi/Model/
dotnet new classlib -n Utils -o F:/work/TApi/Common/ 
dotnet new classlib -n DomainCome -o F:/work/TApi/Services/ 
dotnet new classlib -n Domain -o F:/work/TApi/IServices/ 
dotnet new classlib -n LogicHandle -o  F:/work/TApi/Business/
dotnet new classlib -n ILogicHandle -o  F:/work/TApi/IBusiness/
添加到解决方案
dotnet sln add  F:/work/TApi/Web/UI
dotnet sln add  F:/work/TApi/Data/DB
dotnet sln add  F:/work/TApi/Model/Entity
dotnet sln add  F:/work/TApi/Common/Utils
dotnet sln add  F:/work/TApi/Services/DomainCome
dotnet sln add  F:/work/TApi/IServices/Domain
dotnet sln add  F:/work/TApi/Business/LogicHandle
dotnet sln add  F:/work/TApi/IBusiness/ILogicHandle
在解决方案目录下运行打开Visutal Studio 
devenv /run TApi.sln

运行完结构如下

在这里插入图片描述

添加项目之间引用关系

|- Data 添加 Common,Model引用

dotnet add ./Data/DB/DB.csproj reference ./Common/Utils/Utils.csproj ./Model/Entity/Entity.csproj

|- Services 添加 Common,Model ,IServices引用

dotnet add ./Services/DomainCome/DomainCome.csproj reference ./Common/Utils/Utils.csproj ./Model/Entity/Entity.csproj ./IServices/Domain/Domain.csproj

|- IServices 添加 Data引用

dotnet add ./IServices/Domain/Domain.csproj reference ./Data/DB/DB.csproj

|- IBusiness 添加Common,Model, Services 引用

dotnet add ./IBusiness/ILogicHandle/ILogicHandle.csproj reference ./Common/Utils/Utils.csproj ./Model/Entity/Entity.csproj ./Services/DomainCome/DomainCome.csproj

|- Business 添加IBusiness 引用

dotnet add ./Business/LogicHandle/LogicHandle.csproj reference ./IBusiness/ILogicHandle/ILogicHandle.csproj

|- UI 添加 Common,Model,Business 引用

dotnet add ./Web/UI/UI.csproj reference ./Common/Utils/Utils.csproj ./Model/Entity/Entity.csproj ./Business /LogicHandle/LogicHandle.csproj

下一步 安装EFCore,Nuget包 根据连接字符串生成实体模型到Model层

SqlServer

  1. Microsoft.EntityFrameworkCore
  2. Micorsoft.EntityFrameworkCore.SqlServer
  3. Micorsoft.EntityFrameworkCore.Tools

MySQl

  1. Microsoft.EntityFrameworkCore.Tools
  2. MySql.EntityFrameworkCore
  3. Pomelo.EntityFrameworkCore.MySql

Oracle

  1. Microsoft.EntityFrameworkCore
  2. Oracle.EntityFrameworkCore
  3. Microsoft.EntityFrameworkCore.Tools

4.后端编写CURD 接口 测试

在数据层创建DbContext对象 引入EFCore资源包 重写OnConfiguring方法配置好连接字符串

在这里插入图片描述

编写底层类CURD方法 与 实现

在这里插入图片描述

IBaseServices.cs

 public interface IBaseServices
 {
     T Find<T>(params T[] key) where T : class;
     void UpdateCome<T>(T t,EntityState state) where T : class;
     void UpdateCome<T>(List<T> t, EntityState state) where T : class;
     void UpdateComeAsync<T>(T t, EntityState state) where T : class;
     void UpdateComeAsync<T>(List<T> t, EntityState state) where T : class;
      IQueryable<T> QueryCome<T>(in Expression<Func<T, bool>>[]? whereExp = null) where T : class;
      IQueryable<T> QueryCome<T>(int page = 1, int limit = 10, params Expression<Func<T, bool>>[]? whereExp) where T : class;
     IQueryable<T> QueryCome<T>(out int total, int page = 1, int limit = 10, params Expression<Func<T, bool>>[]? whereExp ) where T : class;
     List<T> QueryCome<T, TOrder>(out int total, int page = 1, int limit = 10,bool isAsc=false, Expression<Func<T,TOrder>>? isOrder=null, params Expression<Func<T, bool>>[]? whereExp) where T : class;
 }

BaseServices.cs

 public class BaseServices(IServiceProvider dbContext) : IBaseServices

 {
     private readonly Test_dbContext _dbContext = dbContext.CreateScope().ServiceProvider.GetRequiredService<Test_dbContext>();

     public T Find<T>(params T[] key) where T : class
     {
         throw new NotImplementedException();
     }
     public  IQueryable<T> QueryCome<T>(in Expression<Func<T, bool>>[]? whereExp = null) where T : class
     {
         IQueryable<T> data= _dbContext.Set<T>();
         if (whereExp != null && whereExp.Length!=0)
         {
             foreach (Expression<Func<T, bool>> item in whereExp)
             {
                 data.Where(item);
             }
         }
         return data;
     }
     public  IQueryable<T> QueryCome<T>(int page = 1, int limit = 10, params Expression<Func<T, bool>>[]? whereExp) where T : class
     {
         IQueryable<T>? data = QueryCome(in whereExp);
         if (page == 0 && limit == 0)
         {
             return data;
         }
         page = (page - 1) * limit;
         return data.Skip(page).Take(limit);
     }
     public IQueryable<T> QueryCome<T>(out int total,int page = 1, int limit = 10, params Expression<Func<T, bool>>[]? whereExp) where T : class
     {
         IQueryable<T>? data = QueryCome(page, limit,whereExp);
         total = data.Count();
         return data;
     }

     public List<T> QueryCome<T, TOrder>(out int total, int page = 1, int limit = 10, bool isAsc = false, Expression<Func<T, TOrder>>? isOrder = null, params Expression<Func<T, bool>>[]? whereExp) where T : class
     {
         IQueryable<T>? data = QueryCome(out total, page, limit, whereExp);
         if (isOrder != null)
         {
             data = isAsc == true ? data.OrderBy(isOrder) : data.OrderByDescending(isOrder);
         }
         return [.. data];
     }

     public void UpdateCome<T>(T t, EntityState state) where T : class
     {
         try
         {
             switch (state)
             {
                 case EntityState.Added:
                     _dbContext.Add(t);
                     break;
                 case EntityState.Deleted:
                     _dbContext.Remove(t);
                     break;
                 case EntityState.Modified:
                     _dbContext.Update(t);
                     break;
                 default:
                     break;
             }
             _dbContext.SaveChanges();

         }
         catch (Exception e)
         {

             throw new Exception(e.Message);
         }
     }

     public void UpdateCome<T>(List<T> t, EntityState state) where T : class
     {
         try
         {
             switch (state)
             {
                 case EntityState.Added:
                     _dbContext.AddRange(t);
                     break;
                 case EntityState.Deleted:
                     _dbContext.RemoveRange(t);
                     break;
                 case EntityState.Modified:
                     _dbContext.UpdateRange(t);
                     break;
                 default:
                     break;
             }
             _dbContext.SaveChanges();

         }
         catch (Exception e)
         {

             throw new Exception(e.Message);
         }
     }

     public void UpdateComeAsync<T>(T t, EntityState state) where T : class
     {
         try
         {
             switch (state)
             {
                 case EntityState.Added:
                     _dbContext.AddAsync(t);
                     break;
                 case EntityState.Deleted:
                     _dbContext.Remove(t);
                     break;
                 case EntityState.Modified:
                     _dbContext.Update(t);
                     break;
                 default:
                     break;
             }
             _dbContext.SaveChanges();

         }
         catch (Exception e)
         {

             throw new Exception(e.Message);
         }
     }

     public void UpdateComeAsync<T>(List<T> t, EntityState state) where T : class
     {
         try
         {
             switch (state)
             {
                 case EntityState.Added:
                     _dbContext.AddRangeAsync(t);
                     break;
                 case EntityState.Deleted:
                     _dbContext.RemoveRange(t);
                     break;
                 case EntityState.Modified:
                     _dbContext.UpdateRange(t);
                     break;
                 default:
                     break;
             }
             _dbContext.SaveChanges();

         }
         catch (Exception e)
         {

             throw new Exception(e.Message);
         }
     }

  
 }

It_userServices.cs

 public interface It_userServices
 {
     void AddUser(t_user t_User);
     int AddUserlist(List<t_user> res);
     List<t_user> QueryUserlist(int page = 1, int limit = 10, int total=0, bool isAsc = false);
 }

t_userServices.cs

  public class t_userServices : It_userServices
  {
      private readonly IBaseServices _baseServices;
      public t_userServices(IBaseServices baseServices) {
          _baseServices=baseServices;
      }
      public void AddUser(t_user t_User)
      {
           _baseServices.UpdateCome(t_User,EntityState.Added);
      }

      public int AddUserlist(List<t_user> res)
      {
          _baseServices.UpdateCome(res,EntityState.Added);
          return 0;
      }

      public List<t_user>? QueryUserlist(int page=1, int limit=10, int total=0, bool isAsc = false)
      {

          List<t_user>? res = _baseServices.QueryCome<t_user, DateTime>(out total, page, limit,  isAsc, d=>d.t_Uptime);
          return res;
      }
  }

在工具层写返回接口结果的抽象类以及用于生成随机数据测试的工具类

在这里插入图片描述

随机数据工具类 太长了 给个外链

http://sb075u42m.sabkt.gdipper.com/RandomTools.cs

​ ApiResult.cs

  public abstract class ApiResult<T>
  {
      public int? Code { get; set; }
      public T? Data { get; set; }
      public string? Message { get; set; }

      public abstract ApiResult<T>? Out(T? Data, int? Code,string? msg);
  }

​ Result.cs

 public class Result<T> : ApiResult<T>
 {
     private Result() { }

     public static readonly Result<T> result = ResultCome.Instance;

     public class ResultCome {
         static ResultCome()
         {
             
         }
         public static Result<T> Instance
         {
             get { 
                 if(result==null)
                     return new Result<T>();
                 else return result;
             }
         }
     }
     public override Result<T> Out(T? Data, int? Code=200, string? msg="")
     {
         switch (Code)
         {
             case 500:
                 result.Code = Code;
                 result.Data = Data;
                 result.Message = msg==""? "请求失败" : msg;
                 return result;
             case 501:
                 result.Code = Code;
                 result.Data = Data;
                 result.Message = msg == "" ? "您没有权限" : msg;
                 return result;
             default:
                 result.Code = Code;
                 result.Data = Data;
                 result.Message = msg == "" ? "请求成功" : msg;
                 return result;
         }
     }
 }

​ QueryParams.cs

public  class QueryParams
{

    static QueryParams()
    {

    }
    public  static QueryParams queryParams=new QueryParams();
   
    public static int Page { get; set; }
    public static int Limit { get; set; }
}

由EF 生成的实体 Model 层下的t_user表映射

 public class t_user
 {
     [Key]
     public string? t_Id { get; set; }
     public string? t_Act { get; set; }
     public string? t_Pwd { get; set; }
     public int t_IsDel { get; set; }
     public int t_State { get; set; }
     public string? t_Code { get; set; }
     public DateTime t_CeTime { get; set; }
     public DateTime t_Uptime { get; set; }  

 }

在Business业务层编写登录逻辑

在这里插入图片描述

It_userLogic.cs

  public interface It_userLogic
  {
      Result<t_user>? Login(string username, string password);
      Result<int>? AddUserList(List<t_user> t_User);
      Result<List<t_user>>? QueryList(QueryParams query);
  }

t_userLogic.cs

  public class t_userLogic : It_userLogic
  {
      private readonly It_userServices _services;
      public t_userLogic(It_userServices services)
      {
          _services = services;
      }

      public Result<int>? AddUserList(List<t_user> t_User)
      {   if (t_User == null) {
              return Result<int>.result.Out(0, 500, "请求失败");
          }
           _services.AddUserlist(t_User);
          return Result<int>.result.Out(1);
      }

      /// <summary>
      /// 用户登录方法
      /// </summary>
      /// <param name="username">用户账户</param>
      /// <param name="password">用户密码</param>
      /// <returns></returns>
      public Result<t_user>? Login(string username, string password)
      {
          if (!string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password)) {
              bool isAny = _services.QueryUserlist().Count != 0;
              if (isAny) {
                  t_user? data = _services.QueryUserlist().Where(d => d.t_Act == username && d.t_Pwd == password).SingleOrDefault();
                  if (data != null) {
                      return Result<t_user>.result.Out(data, 200, "登录成功!");
                  }
                  return Result<t_user>.result.Out(data, 500, "账号或密码错误! 请重新填写");
              }
          }
          return Result<t_user>.result.Out(null,500, "账号密码不能为空!s");
      }

      public Result<List<t_user>> QueryList(QueryParams query)
      {
          bool isAny = _services.QueryUserlist(QueryParams.Page, QueryParams.Limit).Count != 0;
          if (isAny)
          {
             List<t_user>? data=  _services.QueryUserlist(QueryParams.Page, QueryParams.Limit).ToList();
              return Result<List<t_user>>.result.Out(data, 200);
          }
          return Result<List<t_user>>.result.Out(null, 500, "请求失败");
      }
  }

最后在页面层新建用户控制器 接受前端参数进行逻辑处理

在这里插入图片描述

UserController.cs

  [Route("api/[controller]")]
  [ApiController]
  [EnableCors("Any")]
  public class UserController : ControllerBase
  {
      private readonly It_userLogic  _UserLogic;
      public UserController(It_userLogic it_UserLogic)
      {
          _UserLogic= it_UserLogic;
      }
      [HttpPost("Add")]      
      public ActionResult Add([FromQuery] int nums)
      {
          List<t_user>? res = RandomTools<t_user>.RdObj(new t_user { }, nums);
          Result<int>? data= _UserLogic.AddUserList(res);
          return Ok(data);
      }
      [HttpGet("Query")]
      public ActionResult Query([FromQuery] int page,int limit)
      {
          QueryParams.Limit = limit;
          QueryParams.Page = page;
          ApiResult<List<t_user>>? data = _UserLogic.QueryList(QueryParams.queryParams);
          return Ok(data);
      }
      [HttpGet("Login")]
      public ActionResult Login([FromQuery] string act,string pwd)
      {
         ApiResult<t_user>? data= _UserLogic.Login(act,pwd);
         return Ok(data);
      }
  }

这里login登录接受的参数为接口路径后的参数 [FromQuery] 也就是 https://xx/xx/api?xx&xx

现在把写好的api项目接口开始执行

在这里插入图片描述

5.前端请求,路由,接口基础配置

用Vscode 打开之前创建好的项目 新建以下文件夹

在这里插入图片描述

分别 为 接口配置文件夹,测试数据mock文件夹

request请求配置文件夹,router路由配置文件夹,

store Vuex状态配置文件夹 utils工具文件夹
在这里插入图片描述

  1. 配置http
  2. 配置路由router
  3. 配置store
  4. 配置interface
  5. 配置api请求
  6. 配置utils
  7. 配置view页面

request文件夹下

http.ts 这里的请求路径为后端接口的路径

import axios from'axios'const requestInstance=axios.create({//请求路径
    baseURL:"https://localhost:7243/api",//超时时间
    timeout:80000})//请求头
requestInstance.defaults.headers["Content-Type"]="application/json;charset=UTF-8";//请求拦截
requestInstance.interceptors.request.use((res)=>{//做一些处理//const headers=res.headers.get('Authorization')//路由前置守卫 设置传递一些参数returnPromise.resolve(res)},(err:any)=>{returnPromise.reject(err)})//响应拦截
requestInstance.interceptors.response.use((res)=>{//做一些状态码判断returnPromise.reject(res.data)},(err:any)=>{returnPromise.reject(err)})exportdefault requestInstance

methods.ts

import requestInstance from"./http";//封装方法 路径,参数//GET 请求exportconstGET=async(url:string,params:any)=>{try{returnawait requestInstance.get(url, params).then((res)=>{return res
        }).catch((err)=>{return err
        });}catch(err){return err
    }}//POST 请求exportconstPOST=async(url:string,data:any)=>{try{returnawait requestInstance.post(url, data).then((res)=>{return res
        }).catch((err)=>{return err
        });;}catch(err){return err
    }}//PUT 请求exportconstPUT=async(url:string,data:any)=>{try{returnawait requestInstance.put(url, data).then((res)=>{return res
        }).catch((err)=>{return err
        });}catch(err){return err
    }}//DELETE 请求exportconstDEL=async(url:string,data:any)=>{try{returnawait requestInstance.delete(url, data).then((res)=>{return res
        }).catch((err)=>{return err
        });}catch(err){return err
    }}

router文件夹下

路由 index.ts

import{ createRouter, createWebHistory }from"vue-router";const router=createRouter({
    history:createWebHistory(),
    routes:[{
            path:"/",
            name:"home",component:()=>import("@/view/home/index.vue")},{
        path:"/Login",
        name:"Login",component:()=>import("@/view/user/login.vue")},]})exportdefault router

routers.ts

import{ RouteRecordRaw }from'vue-router'exportconst routes:RouteRecordRaw[]=[{
    path:"/",
    name:"home",component:()=>import("@/view/home/index.vue"),
    meta:{
       isChecked:false,
       icon:""},
    children:[{
            path:"home/manage",
            name:"manage",component:()=>import("@/view/home/manage.vue"),}]},{
    path:"/Login",
    name:"Login",component:()=>import("@/view/user/login.vue"),},{
    path:"/attr",
    name:"attr",component:()=>import("@/view/attr/index.vue"),
    children:[{
            path:"attr/config",
            name:"config",component:()=>import("@/view/attr/config.vue"),}]},]

interface文件夹下

user/userformDto.ts

typeuser_loginform={
    act:string|any,
    pwd:string|any}typeuser_dto={
    unick:string,
    uname:string,
    usex:string,
    uage:number,
    ustate:number,
    ucode:string,
    uaddress:string,
    ucreatetime:Date,
    uupdatetime:Date
}exportconst user_formdata:user_loginform={
 act:"",
 pwd:"",}exportconst user_dto:user_dto={
    unick:"",
    uname:"",
    usex:"",
    uage:0,
    ustate:0,
    ucode:"",
    uaddress:"",
    ucreatetime:newDate(),
    uupdatetime:newDate()}

api接口文件夹下

user/api.ts

import{GET,POST}from"@/request/methods"//用户请求接口//登录//创建对应的接口数据 后台Entity 前台DTO对象exportconstlogin=(url:string,params?:any)=>{returnGET(url,params)}//获取用户信息exportconstGetUserInfo=(url:string,params?:any)=>{returnPOST(url,params)}//获取用户列表exportconstGetUserList=(url:string,params?:any)=>{returnGET(url,params)}

store文件夹下

index.ts

import{ createStore }from'vuex'const defaultState ={
  count:0}// Create a new store instance.exportdefaultcreateStore({state(){return defaultState
  },
  mutations:{increment(state:typeof defaultState){
      state.count++}},
  actions:{increment(context){
      context.commit('increment')}},
  getters:{double(state:typeof defaultState){return2* state.count
    }}})

utils文件夹下

handlerCache.ts

exportconstGetCookie=()=>{return}exportconstSetCookie=()=>{return}exportconstSetSession=()=>{return}exportconstGetSession=()=>{return}exportconstGetLocalStorage=()=>{return}exportconstSetLocalStorage=()=>{return}exportconstGetToken=()=>{return}exportconstSetToken=()=>{return}

tools.cs 这里用于生成随机数据作测试 这里给个链接

http://sb075u42m.sabkt.gdipper.com/RandomTools.cs

将view页面根据路由创建好后

编写简单的登录页面

login.vue

<template>
  <div class="Login_box">
    <el-card class="Login_FormContent" shadow="hover">
      <h3>Login in</h3>
      <div class="flex gap-4">
        <div class="Combox_act">
          <el-autocomplete
            v-model="state1"
            :fetch-suggestions="querySearch"
            clearable
            class="inline-input w-50"
            placeholder="账号:"
            @select="handleSelect"
          />
        </div>
        <div class="Combox_pwd">
          <el-autocomplete
            v-model="state2"
            :fetch-suggestions="querySearch"
            :trigger-on-focus="false"
            clearable
            class="inline-input w-50"
            placeholder=" 密码:"
            @select="handleSelect"
          />
        </div>
        <el-button type="primary" plain @click="LoginIn">登录</el-button>
      </div>
    </el-card>
  </div>
</template>
<script type="module" lang="ts" setup>
  import { onMounted, ref } from 'vue'
  import {login} from "@/api/user/api"
import { ElMessage } from 'element-plus';

  interface RestaurantItem {
    value: string
    link: string
  }

  const state1 = ref('')
  const state2 = ref('')

  const restaurants = ref<RestaurantItem[]>([])
  const querySearch = (queryString: string, cb: any) => {
    const results = queryString
      ? restaurants.value.filter(createFilter(queryString))
      : restaurants.value
    // call callback function to return suggestions
    cb(results)
  }
  const createFilter = (queryString: string) => {
    return (restaurant: RestaurantItem) => {
      return (
        restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0
      )
    }
  }
  const loadAll = () => {
    return [
      { value: 'vue', link: 'https://github.com/vuejs/vue' },
      { value: 'element', link: 'https://github.com/ElemeFE/element' },
      { value: 'cooking', link: 'https://github.com/ElemeFE/cooking' },
      { value: 'mint-ui', link: 'https://github.com/ElemeFE/mint-ui' },
      { value: 'vuex', link: 'https://github.com/vuejs/vuex' },
      { value: 'vue-router', link: 'https://github.com/vuejs/vue-router' },
      { value: 'babel', link: 'https://github.com/babel/babel' },
    ]
  }
  const handleSelect = (item: RestaurantItem) => {

    console.log(item)
  }
  //全局引入资源包
//  const tools = import.meta.glob("http://sb075u42m.sabkt.gdipper.com/MyTools.ts")
  const LoginIn=()=>{
    login("/user/login?act="+state1.value+"&pwd="+state2.value+"", {
    }).then((res: any)=>{
      ElMessage({
        type:"success",
        message:"操作成功!"
      })
      console.log("数据请求:",res)
    }).catch((err: any)=>{
      ElMessage({
        type:"error",
        message:err
        })
    })
    // GetUserList("/user/query",{page:10,limit:5}).then((res: any)=>{
    //   ElMessage({
    //     type:"success",
    //     message:"操作成功!"
    //   })
    //   console.log("数据请求:",res)
    // }).catch((err: any)=>{
    //   ElMessage({
    //     type:"error",
    //     message:err
    //     })
    // })
  }
  onMounted(() => {
    restaurants.value = loadAll()
  })
</script>
<style>
.Login_box {
  display: flex;
  justify-content: center;
  align-items: center;
}
.Login_FormContent {
  margin: auto;
  height: auto;
  width: 280px;
  background-color: rgba(238, 242, 249, 0.826);
}
.Combox_act {
  margin: 15px;
}
.Combox_pwd {
  margin: 15px;
}
</style>

6.前端页面请求调用 后端接口Api

打开网址 根据之前配置好的打开为首页
在这里插入图片描述

切换地址到登录页面

输入错误密码请求f12进入页面查看控制台返回数据
在这里插入图片描述

断点请求调试视频如下

前后端分离请求登录断点视频

在后端接口项目挂入断点进行F5调试

在这里插入图片描述

打开数据库复制正确的账号密码进行请求

在这里插入图片描述

输入正确密码进行请求

在这里插入图片描述

欧克 简单的登录就实现啦 觉得对您有帮助的话就点个赞吧

标签: 前端 .net typescript

本文转载自: https://blog.csdn.net/m0_45894394/article/details/142445466
版权归原作者 Awzh Circulate 所有, 如有侵权,请联系我们删除。

“Vue3前端 .NET 后端接口【前后端分离】”的评论:

还没有评论