ASP.NET Core API 前后端分离跨域

news2025/1/16 19:30:42

环境准备

数据库: sqlserver 2022
后端:
vs2022
ASP.NET Core API
.net 8
前端:
Hbuilderx
bootstrap 5.3.0
jquery v3.7.1
bootstrap-table 1.23.5

完整项目代码下载地址

功能

实现 单张表 的 增 删 改 查

创建数据库和表

create database productDB
go
use productDB

-- 创建产品表
CREATE TABLE Products (
    ProductID INT IDENTITY(1,1) PRIMARY KEY, -- 产品ID,自增主键
    ProductName NVARCHAR(100) NOT NULL,     -- 产品名称,最大长度100字符
    Category NVARCHAR(50) NULL,             -- 产品类别,可为空
    Price DECIMAL(10, 2) NOT NULL,          -- 产品价格,保留两位小数
    Stock INT NOT NULL DEFAULT 0,           -- 库存,默认为0
    CreatedDate DATETIME NOT NULL DEFAULT GETDATE(), -- 创建时间,默认为当前时间
    IsActive BIT NOT NULL DEFAULT 1         -- 是否在售,默认在售(1)
);

搭建后台

创建Asp.Net Core API 项目

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

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

安装程序包

Microsoft.EntityFrameworkCore.Tools
Microsoft.EntityFrameworkCore.SqlServer
AutoMapper
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

根据数据库创建Models

在【程序包管理器控制台输入命令】

Scaffold-DbContext 'Data Source=.;Initial Catalog=productDB;User=sa;Password=123456;TrustServerCertificate=true’Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -Context ProductDBContext

-OutputDir Models 输出文件夹:Models
-Context ProductDBContext DBContext类的名称

在这里插入图片描述
执行成功会自动创建DBContext文件和实体类文件
在这里插入图片描述

删除这段代码,后面会在Program.cs中注册DbContext。这里就不需要了
在这里插入图片描述

在appsettings.json中配置数据库连接字符串

在这里插入图片描述

创建dto类 和 添加automap映射配置文件

在这里插入图片描述

namespace ProductDemo.Models.dto
{
    public class ProductDto
    {

        public int? ProductId { get; set; }

        public string? ProductName { get; set; } = null!;

        public string? Category { get; set; }

        public decimal? Price { get; set; } = 0;

        public int? Stock { get; set; } = 0;

        public DateTime? CreatedDate { get; set; }

        public bool? IsActive { get; set; }

    }
}

using AutoMapper;
using ProductDemo.Models.dto;

namespace ProductDemo.Models.config
{
    public class MappingProfile : Profile
    {
        public MappingProfile()
        {
            // 从实体到 DTO 的映射
            CreateMap<Product, ProductDto>();
            CreateMap<ProductDto, Product>();
        }
    }
}

配置Program.cs

添加数据上下文对象依赖注入服务,并从appsettings.json文件中读取连接字符串配置
同时配置跨域
注册autoMap映射

public static void Main(string[] args)
{
    var builder = WebApplication.CreateBuilder(args);

    // Add services to the container.
    

    builder.Services.AddControllers();
    // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
    builder.Services.AddEndpointsApiExplorer();
    builder.Services.AddSwaggerGen();

    //注册autoMap映射
    builder.Services.AddAutoMapper(typeof(MappingProfile));

    //注册DBContext
    builder.Services.AddDbContext<ProductDBContext>(option =>
    {
        option.UseSqlServer(builder.Configuration.GetConnectionString("productDB"));
    });

    //配置跨域
    builder.Services.AddCors(options =>
    {
        options.AddPolicy("cors", builder =>
        {
            builder.AllowAnyOrigin()  //允许任意主机的跨域请求
            .AllowAnyMethod() //允许任意http方法跨域请求
            .AllowAnyHeader(); //允许跨域请求包含任意请求头
        });
    });

    var app = builder.Build();

    //配置和启用cors
    app.UseCors("cors");

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

    app.UseAuthorization();


    app.MapControllers();

    app.Run();
}

创建API控制器

在这里插入图片描述

using AutoMapper;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using ProductDemo.Models;
using ProductDemo.Models.dto;
using System.Security.Cryptography;

namespace ProductDemo.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    [EnableCors("cors")]  //启用跨域
    public class ProductController : ControllerBase
    {
        //创建DBContext对象
        ProductDBContext db ;
        //创建autoMap对象
        IMapper _mapper;
        //注入DbContext
        public ProductController(ProductDBContext db,IMapper mapper)
        {
            this.db = db;
            _mapper = mapper;
        }

        /// <summary>
        /// 分页查询返回值
        /// </summary>
        /// <param name="limit">bootstrap-table默认传递的分页参数</param>
        /// <param name="offset">bootstrap-table默认传递的分页参数</param>
        /// <returns>total和rows是bootstrap-table默认需要的值</returns>
        [HttpGet("GetPageList")]
        public IActionResult GetPageList(int limit,int offset)
        {
            var total = db.Products.Count();
            var rows = db.Products.OrderBy(o=>o.ProductId).Skip(offset).Take(limit).ToList();
            return Ok(new { total = total, rows = rows });
        }

        /// <summary>
        /// 添加
        /// </summary>
        /// <param name="product"></param>
        /// <returns></returns>
        [HttpPost("Add")]
        public IActionResult Add(ProductDto productDto)
        {
            try
            {
                //转换为实体类
                var product = _mapper.Map<Product>(productDto);
                product.CreatedDate = DateTime.Now;
                db.Products.Add(product);
                db.SaveChanges();
                return Ok(new { state = 200, message = "添加成功" });
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
            
        }

        [HttpPost("Edit")]
        public IActionResult Edit(ProductDto productDto)
        {
            //转换为实体类
            var product = _mapper.Map<Product>(productDto);
            try
            {
                var old = db.Products.Find(product.ProductId);
                if (old == null)
                {
                    return NotFound();
                }
                old.ProductName = product.ProductName;
                old.Category = product.Category;
                old.Price = product.Price;
                old.Stock = product.Stock;
                old.IsActive = product.IsActive;

                db.SaveChanges();
                return Ok(new { state = 200, message = "修改成功" });
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }

        [HttpGet("Delete")]
        public IActionResult Delete(int id)
        {
            try
            {
                var old = db.Products.Find(id);
                if(old == null)
                {
                    return NotFound();
                }
                db.Products.Remove(old);
                db.SaveChanges();
                return Ok(new { state = 0, message = "删除成功" });
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }

        

    }
}



启动API后台程序

在这里插入图片描述

编写前端代码

打开Hbuilder创建web项目,并下载好对应的版本

在这里插入图片描述
index.html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>			
		<!-- bootstrap5.3.0 -->
		<link rel="stylesheet" href="plugins/bootstrap-5.3.0-alpha1-dist/css/bootstrap.css" />
				
		<!-- boostrap-table 1.23.5 -->
		<link rel="stylesheet" href="plugins/bootstrapTable/bootstrap-table.css" />
		
		<!-- 图标 -->
		<link rel="stylesheet" href="plugins/bootstrap-icons/bootstrap-icons.css" />

	</head>
	<body>
		<div class="container">
			<div class="toolbar">
				 <button class="btn btn-success" id="btnAdd">
					<i class="bi bi-plus-circle"></i> 添加
				</button>
			</div>
			<table  id="tab"></table>
		</div>
					
		<!-- 添加 修改模态框 -->
		<div class="modal fade" id="staticBackdrop" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" >
		  <div class="modal-dialog">
		    <div class="modal-content">
		      <div class="modal-header">
		        <h1 class="modal-title fs-5" id="staticBackdropLabel">编辑</h1>
		        <button type="button" class="btn-close" data-bs-dismiss="modal" ></button>
		      </div>
		      <div class="modal-body">
		        <form id="dataForm">
		          <div class="mb-3 d-none">
		            <label for="productId" class="form-label"></label>
		            <input type="text" class="form-control" name="productId" id="productId" value="0"  >
		          </div>
		          <div class="mb-3">
		            <label for="productName" class="form-label">商品名称</label>
		            <input type="text" class="form-control" name="productName" id="productName">
		          </div>
				  <div class="mb-3">
				    <label for="category" class="form-label">商品类别</label>
				    <input type="text" class="form-control" name="category" id="category">
				  </div>
				  <div class="mb-3">
				    <label for="Price" class="form-label">商品价格</label>
				    <input type="number" class="form-control" name="Price" id="Price"  value="0" >
				  </div>
				  <div class="mb-3">
				    <label for="Stock" class="form-label">商品库存</label>
				    <input type="number" class="form-control" name="Stock" id="Stock"  value="0" >
				  </div>
		          <div class="mb-3 form-check">
		            <input type="checkbox" class="form-check-input"  id="isActive" name="isActive">
		            <label class="form-check-label" for="isActive">是否启用</label>
		          </div>
		        </form>
		      </div>
		      <div class="modal-footer">
		        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button>
		        <button type="button" class="btn btn-primary" id="btnSave">保存</button>
		      </div>
		    </div>
		  </div>
		</div>
	</body>
	
	<!-- jquery3.7.1 -->
	<script src="js/jquery.js"></script>
	<!--获取表单并序列化-->
	<script src="js/jquery.serializejson.min.js"></script>
	
	<!-- bootstrap5.3.0 -->
	<script src="plugins/popper/poper2.11.8.min.js"></script>
	<script src="plugins/bootstrap-5.3.0-alpha1-dist/js/bootstrap.js"></script>
	
	<!-- boostrap-table 1.23.5 -->
	<script src="plugins/bootstrapTable/bootstrap-table.js"></script>
	<script src="plugins/bootstrapTable/bootstrap-table-zh-CN.js"></script>
	<script>
		$(()=>{
			$('#tab').bootstrapTable({
				url:'http://localhost:5132/api/product/GetPageList',
				pagination:true, //分页
				sidePagination: "server", //服务器分页
				pageNumber:1, 
				pageSize: 10,
				pageList: [10, 20, 50,100],
			  columns: [{
			    field: 'id',
				checkbox:true
			  },{
			    field: 'productId',
			    title: '商品id'
			  }, {
			    field: 'productName',
			    title: '商品名称'
			  }, {
			    field: 'category',
			    title: '商品类别'
			  }, {
			    field: 'price',
			    title: '商品价格'
			  }, {
			    field: 'stock',
			    title: '商品库存'
			  }, {
			    field: 'isActive',
			    title: '是否在售'
			  }, {
			    field: '',
			    title: '编辑',
				formatter:(v,r,i)=>{
					var re =  '<button class="btn btn-warning  btn-sm" οnclick="edit('+i+')">'
								+'<i class="bi bi-pencil-square"></i> 修改'
							+'</button>';
						re += 	 '&nbsp;<button class="btn btn-danger  btn-sm"  οnclick="del('+r.productId+')">'
									+'<i class="bi bi-trash"></i> 删除'
								+'</button>';
					return re;
							
				},
				
			  }]
			})
			
			//添加弹出模态框
			$("#btnAdd").on('click',()=>{
				$("#dataForm")[0].reset();
				$("#staticBackdrop").modal("show");
			});			
			
			//添加or修改
			$("#btnSave").on('click',()=>{
				//jquery.serializejson.min.js 		
				let data = $("#dataForm").serializeJSON();
				if(data.isActive){
					data.isActive=true;
				}				
				let url = "http://localhost:5132/api/product/Add";
				if(data.productId != '0'){
					url = "http://localhost:5132/api/product/Edit";
				}
				$.ajax({
					url:url,
					contentType:"application/json",
					type:"POST",
					data:JSON.stringify(data),
					success:(res)=>{
						$("#staticBackdrop").modal("hide");
						$('#tab').bootstrapTable("refresh")
					},
					error: (xhr, status, error)=> {
						console.log(error);
					}
				})
			});
			
						
		})	
			
		//编辑按钮
		function edit(i){			
			$("#dataForm")[0].reset();
			
			var row = $('#tab').bootstrapTable("getData")[i];
			$.each(row,(k,v)=>{
				if(k=="isActive"){
					 $("#" + k).prop('checked', v);
				}else{					
					$("#"+k).val(v);
				}
			});
			
			$("#staticBackdrop").modal("show");
		}
		
		//删除按钮
		function del(id){
			let data = {
				id : id
			}
			url='http://localhost:5132/api/product/Delete';
			$.ajax({
				url:url,
				contentType:"application/json",
				type:"GET",
				data:data,
				success:(res)=>{
					$('#tab').bootstrapTable("refresh")
				},
				error: (xhr, status, error)=> {
					console.log(error);
				}
			});
		}
	</script>
</html>

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

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

相关文章

Mac M1 安装数据库

1. Docker下载 由于Sqlserver和达梦等数据库&#xff0c;不支持M系列的芯片&#xff0c;所以我们通过docker安装 下载并安装docker: https://www.docker.com/get-started/ 安装完成后&#xff0c;打开docker 2. SQL Server 安装 2.1 安装 打开终端&#xff0c;执行命令 doc…

进程的管理与控制

一、进程与线程 1. 进程 程序&#xff1a;是静态的&#xff0c;就是个存放在磁盘里的可执行文件&#xff0c;就是一系列的指令集合。 进程&#xff08;Process&#xff09;&#xff1a;是指计算机中已执行的程序&#xff0c;是动态的。 &#xff08;1&#xff09;进程的组成…

SQLCipher:SQLite加密工具的实用指南

本文还有配套的精品资源&#xff0c;点击获取 简介&#xff1a;SQLCipher是一个开源工具&#xff0c;用于为SQLite数据库提供透明的数据加密功能&#xff0c;确保数据安全。其工作原理是通过在SQLite的API上增加一层加密层&#xff0c;并使用AES加密算法确保数据在未授权访问…

如何将 JavaWeb 项目部署到云服务器

1. 搭建 Java 部署环境 接下来以 Ubuntu 来进行演示 1.1. apt 包管理工具 apt 就相当于手机上的应用市场 列出所有软件包&#xff1a;apt list 这个命令输出所有包的列表&#xff0c;内容比较多&#xff0c;可以使用 grep 命令过滤输出&#xff1a;apt list |grep "jd…

自动驾驶算法——卡尔曼滤波器平滑感知车道线参数【C++代码实现】

1.算法原理 在工程实践中,由于感知识别到的车道线偶尔存在较大的跳变,导致后端控制算法计算出的控制角度也存在较大的跳变,所以我们需要对感知输入的车道线系数进行平滑处理。 已知卡尔曼滤波算法主要分为以下几大步骤: 感知将车道线以三次螺旋曲线方程 y = c 0 + c 1 x +…

用python替换和循环插入excel的内容

用python替换和循环插入excel的内容 目的&#xff1a; 1.有一个word模板和一个有数据的excel表格 2.需要将excel中的数据经过更改成需要的字符串插入word段落中 3.更改word中的字符串 4.写一个现阶段可以用的程序&#xff0c;并用作以后更新迭代复用。 过程&#xff1a; …

UE5基本数据类型

bool: 表示布尔值&#xff0c;只有两个取值&#xff1a;true 或 false&#xff0c;用于表示逻辑条件。int8: 表示 8 位的有符号整数&#xff0c;范围是 −128−128 到 127127。uint8: 表示 8 位的无符号整数&#xff0c;范围是 00 到 255255。int16: 表示 16 位的有符号整数&am…

【Unity高级】在编辑器中如何让物体围绕一个点旋转固定角度

本文介绍如何在编辑器里让物体围绕一个点旋转固定角度&#xff0c;比如上图里的Cube是围绕白色圆盘的中心旋转45度的。 目标&#xff1a; 创建一个在 Unity 编辑器中使用的旋转工具&#xff0c;使开发者能够在编辑模式下快速旋转一个物体。 实现思路&#xff1a; 编辑模式下…

深度学习:从入门到精通的全面学习路径

摘要&#xff1a; 本文详细阐述了深度学习从入门到精通的系统学习路线。从基础数学与编程知识的夯实&#xff0c;到深度学习核心技术栈的深入掌握&#xff0c;包括 TensorFlow 与 PyTorch 等框架的应用&#xff1b;再到各类主流深度学习算法的原理学习与实践&#xff0c;涵盖神…

CC2530传感器应用实例

1.CC2530流水灯实验 //基于CC2530微控制器的程序&#xff0c;用于控制三个LED灯的闪烁。#include <ioCC2530.h>#define uint unsigned int #define uchar unsigned charuint代表无符号整型&#xff0c;uchar代表无符号字符型。#define LED1 P1_0 #define LED2 P1_1 #defi…

深度和法线纹理

屏幕后期处理效果的基本原理就是当游戏画面渲染完毕后通过获取到该画面的信息进行额外的效果处理 之前的边缘检测、高斯模糊、Bloom、运动模糊等效果都是基于获取当前屏幕图像中的像素信息进行后期处理的 如果仅仅根据像素信息来进行一些效果处理&#xff0c;存在以下问题&…

Oracle之表空间迁移

问题背景&#xff1a;一个数据表随着时间的累积&#xff0c;导致所在表空间占用很高&#xff0c;里面历史数据可以清除&#xff0c;保留近2个月数据即可 首先通过delete删除了2个月以前的数据。 按网上的教程进行空间压缩&#xff0c;以下sql在表所在用户执行: -- 允许表重新…

非父子通信(扩展)-- event bus 事件总线

创建一个空实例Bus&#xff0c; export default 导出Bus 过程:由A组件对Bus组件进行监听&#xff0c;B组件触发Bus对应的事件&#xff0c;由于A组件进行监听&#xff0c;触发事件之后就会进行A组件的回调&#xff0c;那么就可以将消息发送给A了 在src文件夹下新建utils文件夹&a…

vue深入理解(1)

本文章内容主要来源于《vue.js设计与实现》 视图层框架设计 命令式和声明式 范式上&#xff0c;视图层框架通常分为命令式和范式 JQuery就是典型的命令式框架&#xff0c;命令式框架的一大特点就是关注过程 例子&#xff1a; $(#app) // 获取app.text(hello world) // 设置…

CSDN博客如何修改删除上传的资源

CSDN博客是我用过的最好用的博客&#xff0c;它对用户发布文章的限制比较少&#xff0c;而且还支持用户利用知识创新来获取收益&#xff0c;不象51CTO这种垃圾博客&#xff0c;动不动就给扣分限号。但我发现CSDN也有设计缺陷&#xff0c;虽然其上传资源的入口很好找&#xff0c…

【SpringBoot】Day11-10 yml文件配置

三种配置文件 前面我们一直使用springboot项目创建完毕后自带的application.properties进行属性的配置&#xff0c;那其实呢&#xff0c;在springboot项目当中是支持多种配置方式的&#xff0c;除了支持properties配置文件以外&#xff0c;还支持另外一种类型的配置文件&#x…

React路由使用入门react-router-dom

1.安装react-router-dom npm i react-router-dom 2.配置 &#xff08;1&#xff09;创建router实例对象并且配置路由对应关系 &#xff08;2&#xff09;路由绑定 import {createBrowserRouter,RouterProvider} from react-router-dom//&#xff08;1&#xff09;创建rou…

web复习(二)

编程题 1.编写一个函数&#xff0c;接收一个数组作为参数&#xff0c;返回一个对象&#xff0c;其中包含数组中每个元素及其出现次数。 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewpo…

【CANoe示例分析】Basic UDP Multicast(CAPL)

1、工程路径 C:\Users\Public\Documents\Vector\CANoe\Sample Configurations 16.6.2\Ethernet\Simulation\UDPBasicCAPLMulticast 在CANoe软件上也可以打开此工程:File|Sample Configurations|Ethernet - Simulation of Ethernet ECUs|Basic UDP Multicast(CAPL) 2、示例目…

在Linux(ubuntu22.04)搭建rust开发环境

1.安装rust 1.安装curl: sudo apt install curl 2.安装rust最新版 curl --proto ‘https’ --tlsv1.2 https://sh.rustup.rs -sSf | sh 安装完成后出现&#xff1a;Rust is installed now. Great! 重启当前shell即可 3.检验是否安装成功 rustc --version 结果出现&…