1 VScoed快捷键

意义

快捷键

块注释

ctrl+shift+/

行注释

ctrl + /

重开一行

在下方开一行 : ctrl+enter 在上方开一行 : ctrl+shift+enter

移动一行

向上移动 : alt + ↑ 向下移动 : alt + ↓

复制一行

向下复制一行 : shift + alt + ↓ 向上复制一行 : shift + alt + ↑

折叠区域代码

Ctrl + m+ o

2 基础

2.1 杂乱知识

所有 C# 类型(包括 intdouble 等基元类型)均继承自一个根 object 类型。

C# 程序在 .NET 上运行,而 .NET 是名为公共语言运行时 (CLR) 的虚执行系统和一组类库。CLR 是 Microsoft 对公共语言基础结构 (CLI) 国际标准的实现。CLI 是创建执行和开发环境的基础,语言和库可以在其中无缝地协同工作。

程序集 -> CLR -> 实时编译 -> 本机指令

执行 C# 程序时,程序集将加载到 CLR。 CLR 会直接执行实时 (JIT) 编译,将 IL 代码转换成本机指令。

(CLR 可提供其他与自动垃圾回收、异常处理和资源管理相关的服务。 CLR 执行的代码有时称为“托管代码”。而“非托管代码”被编译成面向特定平台的本机语言。)

标识符是变量名称。如果标识符的前缀为 @,则该标识符可以是 C# 保留字。在与其他语言交互时,使用保留字作为标识符很有用。

2.2命令空间

命名空间提供了一种用于组织 C# 程序和库的分层方法。

名称

包含

System

Console

2.3 类型和变量

2.3.1 值类型

数据类型

有符号整型

sbyte、short、int、long

无符号整型

byte、ushort、uint、ulong

字符型

char

IEEE二进制浮点型

float、double

十进制浮点型

decimal

布尔型

bool

枚举型

enum(包含已命名常量的独特类型,值集与基础类型的值集相同) 枚举类型不能定义在方法中

null型

null

元组

格式为(T1,T2,.....)

结构体类型

struct S{......}

强制转换的方法 : (数据类型名称) 变量名

string类的方法 :

String.Compare( strA,strB ) //比较

String.Concat(strA,strB) //链接

详见https://www.runoob.com/csharp/csharp-string.html

C# string 字符串的前面可以加 @(称作"逐字字符串")将转义字符(\)当作普通字符对待

@ 字符串中可以任意换行,换行符及缩进空格都计算在字符串长度之内。

2.3.2 引用类型

名称

类 类型

类 类型的最终基类为 object 如class C{....}

接口 类型

格式 : interface I {...}

数组 类型

如 int[] 或 int[] []

委托 类型

格式 : delegate int D(...) 用户定义的类型

数组类型 : 先定义,后使用

int[] balance = new int[10];
balance[0] = 1;
balance[1] = 2;

2.3.3 区分

class类型 : 包含数据成员、函数成员

struct类型 : 包含数据成员、函数成员的结构(结构是值类型,通常不需要进行堆分配。)

interface类型 : 将协定定义为一组已命名的公共成员。可以继承自多个基接口。由class或struct来实现

delegate 类型 : 表示引用包含特定参数列表和返回类型的方法。 通过委托,可以将方法视为可分配给变量并可作为参数传递的实体。类似“函数指针”

2.3.4 装箱 拆箱

int i = 123;
object o = i;    // Boxing
int j = (int)o;  // Unboxing

将值类型的值分配给 object 对象引用时,会分配一个“箱”来保存此值。

object 引用被显式转换成值类型时,则会将箱中的值复制到值类型。

2.4 程序结构

组织结构概念包括程序、命名空间、类型、成员和程序集。

程序集的文件扩展名通常为 .exe.dll

2.5 main函数

public static void Main() { }
public static int Main() { }
public static void Main(string[] args) { }
public static int Main(string[] args) { }
public static async Task Main() { }
public static async Task<int> Main() { }
public static async Task Main(string[] args) { }
public static async Task<int> Main(string[] args) { }

添加 asyncTaskTask<int> 返回类型可简化控制台应用程序需要启动时的程序代码,以及 Main 中的 await 异步操作。

2.6 输入输出

输出 (打印)

Console.WriteLine(); 输出内容,并换行

Console.Write(); 输出内容,不换行

输入(键盘输入)

Console.Read(); 从屏幕读取一个字符,并返回该字符所对应的整型数字

Console.ReadLine(); 从屏幕读取一串字符,并返回该字符串

int整数类型要将收入的字符串转化为int类型接收

int age=int.parse(Console.ReadLine());

double类型要将收入的字符串转化为double类型接收

double length = double.parse(Console.ReadLine());

解决打印字符 控制台 瞬间关闭的问题:

//在下边加入以下代码
//程序结束后等待用户按下任意键再关闭控制台窗口
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);

输出的占位符

Console.Write("提示字符串内容:{0}",a);

占位符从零开始计数

2.7 封装

  • public:所有对象都可以访问;

  • private:对象本身在对象内部可以访问;

  • protected:只有该类对象及其子类对象可以访问

  • internal:同一个程序集的对象可以访问;

  • protected internal:访问限于当前程序集或派生自包含类的类型。

img

比如说:一个人A为父类,他的儿子B,妻子C,私生子D(注:D不在他家里)

如果我们给A的事情增加修饰符:

  • public事件,地球人都知道,全公开

  • protected事件,A,B,D知道(A和他的所有儿子知道,妻子C不知道)

  • private事件,只有A知道(隐私?心事?)

  • internal事件,A,B,C知道(A家里人都知道,私生子D不知道)

  • protected internal事件,A,B,C,D都知道,其它人不知道

2.8 方法

格式 :

修饰符 函数返回类型 函数名 (参数列表){

函数体

}

注意点:

方法要写在class类中

引用方法时,要使用 class名 变量名 = new class名(); 进行声明

//声明类
class Max
{
    //方法写在类中
     public  int FindMax(int num1, int num2)
        {
            /* 局部变量声明 */
            int result;
​
            if (num1 > num2)
                result = num1;
            else
                result = num2;
​
            return result;
        }
}
internal class Program
{
    static void Main(string[] args)
    {
        //main函数调用时,要先声明这个类,再调用其中的方法
        Max max = new Max();
        int c = max.FindMax(a, b);
    }
}

在 C# 中,使用 ref 关键字声明引用参数.引用参数表示与提供给方法的实际参数具有相同的内存位置。

注意 : 形参前要加ref,传递实参时也需要加ref

按输出传递参数 : return只能返回一个值 , 当想要得到两个返回值时, 可以使用out 来修饰形参,以得到多个返回值.

2.9 函数

构造函数 : 名称与类的名称完全相同,它没有任何返回类型。

析构函数 : 是类的一个特殊的成员函数,当类的对象超出范围时执行。在类的名称前加上一个波浪形(~)作为前缀,它不返回值,也不带任何参数。用于在结束程序(比如关闭文件、释放内存等)之前释放资源

2.10 继承

C# 不支持类的多重继承,但支持接口的多重继承,一个类可以实现多个接口。

概括来说:一个类可以继承多个接口,但只能继承自一个类。

格式 :

class A : B{

}

即A继承B (B为父类,A为子类)

2.11 多态

直接进行重写即可

2.12 特点

  • 三目运算符

格式 : A ? B : C

意义 : 当a为真,则表达式值为b,如果a为假,则表达式值为c

  • datatype ?

    如 int?:表示可空类型,就是一种特殊的值类型,它的值可以为null 用于给变量设初值得时候,给变量(int类型)赋值为null,而不是0

3. 项目结构

3.1 controller

实现的接口在这儿写

格式 :

//使用post请求,写入路由的名称,即接口调用时,浏览器中输入的名称
[HttpPost("RouteName")]
//函数返回类型是IActionResult(状态码),定义FunctionName(函数名),传入DTO类(目的是为了让用户传参)
public IActionResult FunctionName(DTO DTOName)
{
    //DAO类的实例化(DAO是对数据库的封装,)
    DAO  DAOName = new DAO();
    
    //将DTO的值赋给DAO(即将用户输入的信息,传给数据库的字段)
    DAOName.Member = DTOName.Member;
    ......
        
    //调用DAO方法(DAO继承TableModelMSSQL,故有其中的方法)
    DAOName.Add();
    DAOName.GetModel(" DepartmentID = 1");
    
    return StatusCode(StatusCodes.Status400BadRequest, UtilHelper.Output("40000001")); //代表插入成功
}

3.2 common

SysConstant : 系统常量. 比如SQL Server的配置字符串在此定义

DbHelperMSSQL: 操作数据库的类

函数名

参数

返回值类型

作用

GetMaxID(string FieldName, string TableName)

FieldName:字段名 TableName:表名

int

将FieldName字段中的最大值+1 (可能适用于表尾的插入操作)

GetMinID(string FieldName, string TableName)

FieldName:字段名 TableName:表名

int

将FieldName字段中的最小值 (可能适用于表头的插入操作)

Exists(string strSql)

strSql:sql语句

bool

判断传入的sql语句执行后,是否有查询结果

Exists(string strSql, SqlParameter[] cmdParms)

strSql:sql语句 cmdParms:sql参数

bool

判断传入的sql语句和对应的参数执行后,是否有查询结果

ExecuteSql(string SQLString)

SQLString:sql语句

int

传入sql语句,执行该sql,并返回受影响的行数

GetSingle(string SQLString)

SQLString:计算查询结果语句

object

传入查询结果的sql语句,执行该语句,并返回查询结果

Query(string SQLString)

SQLString:查询语句

DataSet

传入查询的sql语句,执行该语句,并将查询结果赋值给DataSet ,最后返回DataSet

ExecuteSql(string SQLString, params SqlParameter[] cmdParms)

SQLString:sql语句 cmdParms:sql参数

int

传入sql语句和对应的参数,执行该语句,并返回受影响的行数

GetData(string sql)

sql : 查询单行单列的语句

float

传入查询单行单列的sql语句,执行该语句,并返回查询到的值

GetSingle(string SQLString, params SqlParameter[] cmdParms)

SQLString :计算查询结果语句 cmdParms : sql参数

object

传入一条计算查询结果的sql语句,执行语句,并返回查询结果

UtilHelper : 操作辅助类

3.3 model

dao:

(data access object 数据访问对象) , 包含对数据的访问,负责持久层的操作 。封装数据库

格式:

using Tiliatech.IECS_API.Common;
using Tiliatech.IECS_API.Model.DAO;

namespace WebApplication2.Models.DAO
{
    //首先要继承TableModelMSSQL(各种操作数据库的方法)
    public class BaseUser :TableModelMSSQL
    {
        //定义构造方法,获取数据库名称
        public BaseUser()
        {
            //UtilHelper是一个公用类,调用其中的获取数据库名称的方法
            //GetColumns是TableModelMSSQL中的一个方法,传入数据库名称,传入表名称,得到数据库列
            TableColumnMSSQLs = GetColumns(UtilHelper.DB_NAME, "Employees");
        }
        //定义成员
        private int _EmployeeID;
        private string _Name;
        private int _DepartmentID;


        //获取数据库字段
        public int EmployeeID { get => _EmployeeID; set => _EmployeeID = value; }
        public string Name { get => _Name; set => _Name = value; }
        public int DepartmentID { get => _DepartmentID; set => _DepartmentID = value; }
    }
}

TableModelMSSQL中的方法 :

函数名

参数

返回值类型

作用

Add() √

int sql计算查询结果转为int型

insert intoTableName ( 字段1,字段2,字段3...) values (值1,值2,值3...);

DataRowToModel()

DataTableToList()

BuildMenuTree()

GetColumns()

GetList()

GetSum()

GetRw()

GetModel() √

string strWhere

void

select * FROM TableName where {strWhere} 将查询到的结果赋到DAO对象中

GetTotal() √

string strWhere

int

select count(0) FROM TableName where {strWhere} 传入条件strWhere.查询表中满足该条件的行数

Update() √

string strWhere

bool

update TableName set 字段1=值1,字段2=值2,字段3=值3,.... where {strWhere} 传入条件strWhere,修改第一个满足该条件的行

UpdatePart()

string strQuery, string strWhere

bool

update TableName {strQuery} where {strWhere}

UpdateFiled() √

string filed, string strWhere

bool

update TableName set {filed} where {strWhere} 传入条件strWhere,修改字段filed的值

DeletePart() √

string strWhere

bool

DELETE FROM TableName where {strWhere} 传入条件strWhere,删除第一个满足该条件的行

Exists()

int id, string pKey = "id"

bool

SELECT COUNT(0) FROM TableName WHERE {pKey} ={id} 传入id(主键的序号),传入主键pKey ,查看其是否存在于表中

Exists() √

string strWhere

bool

SELECT COUNT(0) FROM TableName WHERE {strWhere} 传入条件strWhere,查看是否有这条记录

GetMaxNum() √

string num

int

select max({num }) from TableName 传入字段num , 返回该字段中最大的值

GetMinNum() √

string num

int

select min({num }) from TableName 传入字段num , 返回该字段中最小的值

dto:

(Data Transfer Object 数据传输对象),表示用户信息的数据传输对象, 在进行请求时,应用在接口接收传入对象,然后又转换成实体进行持久化。在此过程中,传入的对象就是DTO.

如:

namespace WebApplication2.Models.DTO
{
    public class UserDTO
    {

        public int EmployeeID { get; set; }
        public string Name { get; set; }
        public int DepartmentID { get; set; }
    }
}

调用逻辑 : 客户端发送请求 -> 顶级类 -> controller

4. webAPI

4.1 新建项目

ASP.NET Core Web API

4.2 controller下做接口

using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;

namespace WebApplication2.Controllers
{
    //1 . 声明接口
    [ApiController]
    //2. 一级接口路径(路由:api接口的路径)
    [Route("test")]

    // 3. 继承ControllerBase
    public class TestController : ControllerBase
    {
        //4.添加接口的注释
        
        ///<summary>该接口的作用是什么</summary>
        ///<param name="形参名称">要传入的参数是什么</param>
        ///<returns>返回什么值</returns>
        
        //5. 写接口
        [HttpGet("getUsers")] //接口类型()中填写的是二级路径
        //当一个动作中有多个ActionResult返回类型时,IActionResult返回类型是合适的。
        //ActionResult类型代表各种HTTP状态代码。
        public IActionResult ADSD()
        {
            return StatusCode(StatusCodes.Status400BadRequest, ("40000001"));
        }


        [HttpGet("getUserById")]
        //如使用get请求获取参数,直接在该函数中定义形参即可
        public int GetUserById(int id)
        {
            return id;
        }
        
    }
}

4.3 路由设计

  • Route为api接口的路径

  • [controller]是所在文件的名称的前缀,如现在的文件名为TestController,则controller的值为Test

  • [action] 是函数方法的名称

  • [HttpGet("")] 或 [HttpPost("")] 或 [HttpPut("")] 或 [HttpPatch("")] 或 [HttpDelete("")] , 指定了接口的类型,()中也可填写路径

如 : 路由为[Route("api/[controller]/[action]")] , 后边跟有 [HttpPost("POST/employees")]

则会被拼接为

4.4 注解

  • [Authorize] : 完成一些简单的权限管理功能

  • [PermissionFilter] : 用于过滤权限的机制 . 在开发中,我们通常需要对不同用户或用户组进行权限控制,以确保不同角色只能访问其具备权限的资源或执行特定操作。

4.5 返回值

return StatusCode(StatusCodes.xxx, "");

4.6 执行

4.7 发布

右键 -> 发布

点击发布

5. 连接SQL Server

  1. 先导入库包

    using System.Data;  // 表的命名空间
    using System.Data.SqlClient;    // 和SQL相关的命名空间

  2. 数据库配置信息

    数据库名称 : MSSQLSERVER 使用SSMS连接时,输入的服务器名称 : DESKTOP-DKL\localhost 数据库用户名 : sa 数据库密码 : 123456

  3. VS Code里下载nuGet包

    System.Data.SqlClient

  4. 连接数据库

//定义一个字符串(里边包含数据库的配置项信息)
String sqlcon = "Server=服务器名; Database=数据库名; uid = 用户名; pwd = 密码; Trusted_Connection = False;"
//实例化数据库对象,传入配置项sqlcon
SqlConnection con = new SqlConnection(sqlcon);
//打开数据库
con.Open();

本台电脑的配置如下:

Server=localhost; Database=TestBase; uid = sa; pwd = 123456; Trusted_Connection = False;

  1. 操作数据库

//定义sql语句
String sql = "sql语句";
//创建sql命令对象cmd,传入sql语句和数据库对象con
SqlCommand cmd = new SqlCommand(sql,con);
//创建sql接收器对象adapter,传入sql命令对象cmd //DataAdapter 是用于在 DataSet 和数据源之间进行数据交换的桥梁
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
//创建DataSet 对象ds,DataSet用于存储和处理数据
DataSet ds = new DataSet();
//adapter中的数据填充到ds当中,接下来即可通过 DataSet 对象(ds)来访问和操作从数据库中检索到的数据
adapter.Fill(ds);

//使用DataTable来接收查询结果
DataTable dt = ds.Tables[0]; //dt得到第一个表的数据
DataRow dr = dt.Rows[0]; //dr得到表中第一行数据
//验证查询结果    
System.Console.WriteLine(dr["name"]); //输出第一行字段为name的值

6. Restful API

6.1 URL 设计

客户端发出的数据操作指令都是"动词 + 宾语"的结构 , 如 /articles

HTTP 方法

对应 CRUD 操作

GET

读取

POST

新建

PUT

更新

PATCH

更新(部分)

DELETE

删除

若有些客户端只能使用GETPOST这两种方法 , 如何表示其他三个方法?

使用POST模拟其他三个方法(PUTPATCHDELETE)。

客户端发出的 HTTP 请求,要加上X-HTTP-Method-Override属性

POST /api/Person/4 HTTP/1.1  
X-HTTP-Method-Override: PUT

注意点:

  • 动词一律大写,宾语必须是名词.

    如动词GET , 宾语articles

  • 避免多级 URL . 最佳的做法是 : 除了第一级,其他级别都用查询字符串表达。

    如GET /articles?published=true , 而不是GET /articles/published

6.2 状态码设计

客户端的每一次请求,服务器都必须给出回应。回应包括 HTTP 状态码数据两部分。

HTTP 状态码

含义

1xx

相关信息

2xx

操作成功

3xx

重定向

4xx

客户端错误

5xx

服务器错误

6.2.1 2xx状态码 -> 操作成功

  • GET: 200 OK

  • POST: 201 Created

  • PUT: 200 OK

  • PATCH: 200 OK

  • DELETE: 204 No Content

POST返回201状态码,表示生成了新的资源;

DELETE返回204状态码,表示资源已经不存在。

202 Accepted状态码表示服务器已经收到请求,但还未进行处理,会在未来再处理,通常用于异步操作。

6.2.2 3xx状态码 -> 重定向

// 301/302重定向可以由应用级别返回,浏览器会直接跳转,API 级别可以不考虑这两种情况。这种是直接跳转

  • 303 是API 用到的状态码,表示参考另一个 URL。浏览器不会自动跳转,而会让用户自己决定下一步怎么办。

6.2.3 4xx状态码 -> 客户端错误

状态码

含义

400 Bad Request

服务器不理解客户端的请求,未做任何处理

401 Unauthorized

用户未提供身份验证凭据,或者没有通过身份验证

403 Forbidden

用户通过了身份验证,但是不具有访问资源所需的权限

404 Not Found

所请求的资源不存在,或不可用

405 Method Not Allowed

用户已经通过身份验证,但是所用的 HTTP 方法不在他的权限之内

410 Gone

所请求的资源已从这个地址转移,不再可用

415 Unsupported Media Type

客户端要求的返回格式不支持 比如,API 只能返回 JSON 格式,但是客户端要求返回 XML 格式

422 Unprocessable Entity

客户端上传的附件无法处理,导致请求失败

429 Too Many Requests

客户端的请求次数超过限额

6.2.4 5xx状态码 -> 服务器错误

API 不会向用户透露服务器的详细信息,所以只要两个状态码就够了。

状态码

含义

500 Internal Server Error

客户端请求有效,服务器处理时发生了意外

503 Service Unavailable

服务器无法处理请求,一般用于网站维护状态

6.3 服务器回应

6.3.1 服务器要返回JSON对象

  • API 返回的数据格式,不应该是纯文本,而应该是一个 JSON 对象

  • 服务器回应的 HTTP 头的Content-Type属性要设为application/json

  • 客户端请求时,也要告知服务器可以接受 JSON 格式,即请求的 HTTP 头的ACCEPT属性也要设成application/json

IHttpActionResult是WebApi最常用的一种返回值类型,常用的方式有:Json(T content)、Ok()、 Ok(T content)、NotFound()、Content(HttpStatusCode statusCode, T value)、BadRequest()、Redirect(string location)等

6.3.2 正确使用状态码

错误做法 : 即使发生错误,还返回200状态码,把错误信息放在数据体里面

HTTP/1.1 200 OK
Content-Type: application/json

{
  "status": "failure",
  "data": {
    "error": "Expected at least two items in list."
  }
}

正确做法 : 状态码反映发生的错误,具体的错误信息放在数据体里面返回

HTTP/1.1 400 Bad Request
Content-Type: application/json

{
  "error": "Invalid payoad.",
  "detail": {
     "surname": "This field is required."
  }
}

6.3.3 提供API链接

HATEOAS方法 : 在回应中,给出相关链接,便于下一步操作。用户只要记住一个 URL,就可以发现其他的 URL。

如GitHub 的 API 都在 api.github.com 这个域名

[Route("api/[controller])]

[Route("api/[action]")]

7. 数据库构建

  • 创建数据库

CREATE TABLENAME
(
字段1 dataType primary key,
字段1 dataType,
字段1 dataType,
字段1 dataType,
字段1 dataType
);

dataType

int

整型

varchar

字符型

text

字符型(适用于字符多的情况)

data

日期(YYYY-MM-DD)

dataTime

日期和时间值(YYYY-MM-DD HH:MM:SS)

timestamp

自动存储记录修改时间

  • 主键字段自增操作

先创建一个序列

CREATE SEQUENCE name_seq;

到主键上 , 进行绑定序列

nextval('name_seq'::regclass)

8. model数据库表对象模版

/// <summary>
/// 表名
/// </summary>
public class FildName : TableModel
{
    //构造函数
    public FildName()
    {
        this.TableColumns = this.GetColumns(UtilHelper.DB_NAME, "TableName");
    }
    //私有成员
    private int _field1;
	
    //get\set方法以访问和设置私有成员的值
    public int replen_drug_id { get => _field1; set => _field1 = value; }
}

9. CRUD代码模版

//日期数据赋值
UtilHelper.LocalDateTime().AddHours(8)
//创建人\ 更新人 赋值
UtilHelper.GetUserInfo(HttpContext)
//数据格式转换(主要应用场景 : 字符串转数值型,数值型转字符串)
Convert.Toint32(str1) //字符串转整型
variable.ToSafeString() //数值型转字符串型

9.1 增加操作

  1. 传入JObject data

  2. 设置一个大的try catch

  3. 对传入的data进行判空操作

  4. 使用QsJsonHelper.JGetJsonAttr() 方法 , 将json数据中的键值取出来 (存入变量中)

  5. 对不为null的字段进行格式校验

  6. 实例化数据库对象

  7. 判断数据库中是否存在要插入的数据

  8. 对数据库对象的成员进行赋值操作

  9. 使用Add()方法 , 传入主键 , 进行添加操作

  10. 使用GetModel()方法 , 获取数据

  11. 使用UtilHelper.zhObj() , 传入数据库对象 , 进行json封装

  12. 日志记录插入成功 , 返回状态码

		/// <summary>
        /// XX添加
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        /// <remarks>
        /// 请求参数示例:
        /// ````````
        ///{
        ///"field1": "value1",
        ///"field2": "value2",
        ///"field3": "value3",
        ///"field3": "value4",
        ///"field4" : "value5"
		///
        ///}
        ///</remarks>

        [HttpPost("apiName")]
		public IActionResult AddapiName(JObject data)
        {
            try
            {
                //传入数据为空时 , 返回错误状态码
                if (data == null)
                {
                    return StatusCode(StatusCodes.Status400BadRequest, UtilHelper.JOutput("401"));
                }
                #region 获取json中的属性值
                string field1 = QsJsonHelper.JGetJsonAttr(data, "field1");
                
                #endregion
                
                #region 非空格式校验
                if (string.IsNullOrEmpty(field1) || string.IsNullOrEmpty(field2))
                {
                    return StatusCode(StatusCodes.Status400BadRequest, UtilHelper.JOutput("401"));
                }
                
                #endregion
                
                //实例化TableName对象
                TableName tableName = new TableName();
                
                //判断是否存在具有唯一性的字段值
                //若存在脉诊编码或脉诊名称 , 则返回错误状态码
                if (baseTcmPulseDiagnosis.Exists($"field1 ='{field1}'"))
                {
                    return StatusCode(StatusCodes.Status400BadRequest, UtilHelper.JOutput("401"));
                }
                
                #region 对tableName的成员进行赋值操作
                tableName.field1 = field1;
                
                #endregion
                
                //进行添加操作 , 并判断是否插入成功
                int success = baseTcmPulseDiagnosis.Add("pkey");
                if (success <= 0)
                {
                    return StatusCode(StatusCodes.Status400BadRequest, UtilHelper.JOutput("401"));
                }
                
                //读取数据
                baseTcmPulseDiagnosis.GetModel($"field1 = '{field1}'");
                
                //封装json
                JObject res = UtilHelper.zhObj(tableName);
                
                //或自主封装(2选1)
                JObject res = new JObject()
				{
                    
                };
                //插入成功 , 记录日志
                LogHelper.LogOper("1", "XX", UtilHelper.GetUserInfo(HttpContext), "1", "添加");
                //返回插入成功的状态码和json数据
                return StatusCode(StatusCodes.Status200OK, UtilHelper.JOutput("201", res));
            }
            catch (Exception ex)
            {
                return StatusCode(StatusCodes.Status500InternalServerError, UtilHelper.JOutput("50000001"));
            }
            
        }

9.2 批量增加

        /// <summary>
        /// XX批量添加
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        /// <remarks>
        /// 请求参数示例:
        /// ````````
        ///{
        /// "array": [{
        ///           "field1":"value1",
        ///           "field2":"value2",
        ///           "field3":"value3",
        ///           "field4":"value4",
        ///           "field5":"value5"
        ///            },
        ///            {
        ///           "field1":"value1",
        ///           "field2":"value2",
        ///           "field3":"value3",
        ///           "field4":"value4",
        ///           "field5":"value5"
        ///            }],
        ///  "ppzd":["field1","field2"],
        ///  "nrcz":1
        /// }
        ///</remarks>

        [HttpPost("apiNames")]
         public IActionResult AddapiNames(JObject item)
         {
            //获取json的值(array中是所有要插入的数据)
            string zybmarray = QsJsonHelper.JGetJsonAttr(item, "array", "[]");
            //ppzz(匹配字段) , 值唯一的字段
            string ppzd = QsJsonHelper.JGetJsonAttr(item, "ppzd", "[]");
            //nrcz是一种处理重复的策略 : 1.覆盖 2.跳过
            string nrcz = QsJsonHelper.JGetJsonAttr(item, "nrcz");
            //匹配名称
            string ppmc = "";
            //编号
            string bh = "";

            //dataArray中包含所有要插的数据值
            JArray dataArray = JArray.Parse(zybmarray);
            //ppzdArray中包含所有值唯一的字段
            JArray ppzdArray = JArray.Parse(ppzd);
            if (ppzdArray.Count == 0)
            {
                return StatusCode(StatusCodes.Status400BadRequest, UtilHelper.JOutput("401"));
            }
            
            //循环匹配字段数组
            foreach (var zdobj in ppzdArray)
            {
                //格式验证
                if (zdobj.ToString() != "field1" && zdobj.ToString() != "field2")
                {
                    return StatusCode(StatusCodes.Status400BadRequest, UtilHelper.JOutput("401"));
                }
                //赋值
                if (zdobj.ToString() == "field1")
                {
                    ppmc = zdobj.ToString();
                }
                if (zdobj.ToString() == "field2")
                {
                    bh = zdobj.ToString();
                }
            }
			
            //判空
            if (dataArray == null || dataArray.Count == 0)
            {
                return StatusCode(StatusCodes.Status400BadRequest, UtilHelper.JOutput("401"));
            }

            try
            {
                
                JArray resArray = new JArray();
                //格式校验
                foreach (JObject data in dataArray)
                {
                    #region 获取参数
                    string field1 = QsJsonHelper.JGetJsonAttr(data, "field1");
                    string field2 = QsJsonHelper.JGetJsonAttr(data, "field2");
                    
                    #endregion

                    //格式校验
                    if (string.IsNullOrEmpty(field1) || string.IsNullOrEmpty(field2))
                    {
                        return StatusCode(StatusCodes.Status400BadRequest, UtilHelper.JOutput("401"));
                    }
                }


                //开启事务
                using (var scope = new TransactionScope())
                {
                    foreach (JObject data in dataArray)
                    {
                        #region 获取json中的属性值
                        string field1 = QsJsonHelper.JGetJsonAttr(data, "field1");
                        
                        #endregion


                        //实例化TableName对象
                        TableName tableName = new TableName();
                        string where = "";
                        //id和名字都一起判断
                        if (!string.IsNullOrEmpty(ppmc) && !string.IsNullOrEmpty(bh))
                        {
                            where = "field1 = " + $"'{field1}'" + " AND " + "field2 = " + $"'{field2}'";
                        }
                        
                        //名字判断
                        else if (!string.IsNullOrEmpty(ppmc) && string.IsNullOrEmpty(bh))
                        {
                            where = "field2 = " + $"'{field2}'";
                        }
                        //id判断
                        else if (string.IsNullOrEmpty(ppmc) && !string.IsNullOrEmpty(bh))
                        {
                            where = "field1 = " + $"'{field1}'";
                        }
                        
                        //判断匹配字段
                        if (tableName.Exists(where))
                        {
                            //判断是否覆盖:1.覆盖。其他跳过
                            if (nrcz == "1")
                            {
                                //添加前判断配覆盖的主键是否已存在
                                if (string.IsNullOrEmpty(bh))
                                {
                                    if (tableName.Exists("field1 = " + $"'{field1}'"))
                                    {
                                        scope.Dispose();
                                        return StatusCode(StatusCodes.Status400BadRequest, UtilHelper.JOutput("401"));
                                    }
                                }
                                if (string.IsNullOrEmpty(ppmc))
                                {
                                    if (tableName.Exists("field2 = " + $"'{field2}'"))
                                    {
                                        scope.Dispose();
                                        return StatusCode(StatusCodes.Status400BadRequest, UtilHelper.JOutput("401"));
                                    }
                                }
                                tableName.GetModel(where);
                                
                                #region 赋值
                                tableName.field1 = field1;
                                
                                #endregion

                                //封装json
                                JObject ress = UtilHelper.zhObj(tableName);
                               
                                //返回值添加
                                resArray.Add(ress);
                                continue;
                            }
                            else
                            {
                                continue;
                            }
                        }

                        //添加时判断是否存在
                        if (tableName.Exists("field1 = " + $"'{field1}'"))
                        {
                            scope.Dispose();
                            return StatusCode(StatusCodes.Status400BadRequest, UtilHelper.JOutput("401"));
                        }
                        
                        //封装
                        tableName.field1 = field1;
                       
                        //封装json
                        JObject res = UtilHelper.zhObj(tableName);

                        resArray.Add(res);
                    }
                    scope.Complete();
                }

                //插入成功 , 日志记录并返回状态码
                LogHelper.LogOper("1", "XX", UtilHelper.GetUserInfo(HttpContext), "1", "添加");
                return StatusCode(StatusCodes.Status200OK, UtilHelper.JOutput("201", resArray));
            }
            catch (Exception ex)
            {
                return StatusCode(StatusCodes.Status500InternalServerError, UtilHelper.JOutput("50000001");
            }
         }

9.3 删除操作

  1. 传入主键

  2. 判断主键是否合法

  3. 实例化数据库表对象

  4. 查询该条数据是否存在于表中 , 不存在则无法删除

  5. 调用DeletePart()方法 , 进行删除

  6. 判断是否删除成功 , 若不成功 , 记录删除不成功日志 , 返回错误码

  7. 若成功 , 记录删除成功日志 , 返回正确码

        /// <summary>
        /// XX删除
        /// </summary>
        /// <param name="field1"></param>
        /// <returns></returns>
        /// <remarks>
        /// 请求参数示例
        /// mzbh : 1
        /// </remarks>
        [HttpDelete("apiName/{field1}")]
        public IActionResult DeleteapiName(int field1)
        {
            try
            {
                //如果主键编号不合法 , 返回错误状态码
                if(field1 <= 0)
                {
                    return StatusCode(StatusCodes.Status400BadRequest, UtilHelper.JOutput("402"));
                }

                //实例化TableName对象
                TableName tableName = new TableName();

                //若查询到该条数据不存在于表中 , 则无法删除 , 返回错误状态码 
                if (!tableName.Exists($"field1 ='{field1}'"))
                {
                    return StatusCode(StatusCodes.Status400BadRequest, UtilHelper.JOutput("402"));
                }

                //删除操作
                bool sucess = baseTcmPulseDiagnosis.DeletePart($"field1 ='{field1}'");

                //删除不成功 , 日志记录删除失败
                if (!sucess)
                {
                    LogHelper.LogOper("3", "XX", UtilHelper.GetUserInfo(HttpContext), "0", "删除");
                    return StatusCode(StatusCodes.Status400BadRequest, UtilHelper.JOutput("402"));
                }
                //删除成功 , 日志记录删除成功
                LogHelper.LogOper("3", "XX", UtilHelper.GetUserInfo(HttpContext), "1", "删除");
                return StatusCode(StatusCodes.Status200OK, UtilHelper.JOutput("202"));
            }
            catch (Exception ex)
            {
                return StatusCode(StatusCodes.Status500InternalServerError, UtilHelper.JOutput("50000001"));
            }
        }

9.4 批量删除

        /// <summary>
        /// XX批量删除
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        /// <remarks>
        /// 请求参数示例:
        /// ```
        /// {
        ///     "ids": "['1','2']"
        /// }
        /// </remarks>
        [HttpDelete("apiName")]
        public IActionResult DeleteapiName(JObject data)
        {
            try
            {
                //数据为空 , 返回错误状态码
                if (data == null)
                {
                    return StatusCode(StatusCodes.Status400BadRequest, UtilHelper.JOutput("402"));
                }
                
				//json放到JArray数组中
                JArray ids = JArray.Parse(data["ids"].ToString() == null ? "[]" : data["ids"].ToString());

                //格式判断
                if (ids.Count == 0)
                {
                    return StatusCode(StatusCodes.Status400BadRequest, UtilHelper.JOutput("402"));
                }

                //实例化TableName对象
                TableName tableName = new TableName();

                //拼接sql
                StringBuilder str = new StringBuilder();
                str.Append($"pkey in (");
                foreach (int obj in ids)
                {
                    str.Append($"{obj},");
                }
                str.Append(")");
                str.Remove(str.Length - 2, 1);

                //删除加判断
                if (tableName.DeletePart(str.ToString()))
                {
                    LogHelper.LogOper("3", "XX", UtilHelper.GetUserInfo(HttpContext), "1", "删除");
                    return StatusCode(StatusCodes.Status200OK, UtilHelper.JOutput("202"));
                }
                else
                {
                    LogHelper.LogOper("3", "XX", UtilHelper.GetUserInfo(HttpContext), "0", "删除");
                    return StatusCode(StatusCodes.Status400BadRequest, UtilHelper.JOutput("402"));
                }

            }
            catch (Exception ex)
            {
                return StatusCode(StatusCodes.Status500InternalServerError, UtilHelper.JOutput("50000001");
            }
        }

9.5 修改操作

  1. 传入JObject data , 传入主键

  2. 判断data是否为null 或 要修改的逐渐编号是否合法

  3. 获取json中的属性值

  4. 格式校验

  5. 实例化数据库表对象

  6. 判断是否存在传入的主键编号

  7. 调用GetModel()方法获取数据

  8. 对数据库表对象的成员进行赋值

  9. 调用Update()方法进行修改操作

  10. 若不成功 , 则记录失败日志 , 返回错误状态码

  11. 使用UtilHelper.zhObj() , 传入数据库对象 , 进行json封装

  12. 日志记录插入成功 , 返回状态码

        /// <summary>
        /// XX修改
        /// </summary>
        /// <param name="data"></param>
		/// <param name="pkey"></param>
        /// <returns></returns>
        /// <remarks>
        /// 请求参数示例:
        /// ```
        /// pkey : 1
        /// change : 
        ///{
        ///"field1": "value1",
        ///"field2": "value2",
        ///"field3": "value3",
        ///"field4": "value4",
        ///
        ///}
        /// </remarks>

        [HttpPut("apiName/{pkey}")]
        public IActionResult PutapiName(JObject data, int pkey)
        {
            try
            {
                //若传入的修改数据为null 或要修改的编号不合法 , 直接返回错误状态码  
            	if(data == null || pkey <= 0)
            	{
                	return StatusCode(StatusCodes.Status400BadRequest, UtilHelper.JOutput("403"));
            	}
                
                #region 获取json中的属性值
                string field1 = QsJsonHelper.JGetJsonAttr(data, "field1");
                
                #endregion


                //格式校验
                if (string.IsNullOrEmpty(field1) || string.IsNullOrEmpty(field2))
                {
                    return StatusCode(StatusCodes.Status400BadRequest, UtilHelper.JOutput("403"));
                }

                //实例化TableName对象
                TableName tableName = new TableName();

                //若不存在要修改的脉诊编号 , 则返回错误状态码
                if (!tableName.Exists($"pkey ='{pkey}'"))
                {
                    return StatusCode(StatusCodes.Status400BadRequest, UtilHelper.JOutput("403"));
                }
                //拿到数据
                tableName.GetModel($"pkey ='{pkey}'");

                #region 赋值
                tableName.field1 = field1;
                
                #endregion

                //修改操作
                bool success = tableName.Update("pkey");
                //不成功 , 记录不成功的日志
                if (!success)
                {
                    LogHelper.LogOper("2", "XX", UtilHelper.GetUserInfo(HttpContext), "0", "修改");
                    return StatusCode(StatusCodes.Status400BadRequest, UtilHelper.JOutput("403"));
                }

                //封装为json
                JObject res = UtilHelper.zhObj(tableName);

                //成功
                LogHelper.LogOper("2", "XX", UtilHelper.GetUserInfo(HttpContext), "1", "修改");
                return StatusCode(StatusCodes.Status200OK, UtilHelper.JOutput("203", res));
            }
            catch (Exception ex )
            {
                return StatusCode(StatusCodes.Status500InternalServerError, UtilHelper.JOutput("50000001"));
            }
        }

9.6 查看操作

  1. 传入主键的值

  2. 判断主键值是否合法

  3. 实例化数据库表对象

  4. 查看表中是否有该条数据 , 不存在则返回状态码

  5. 调用GetModel()方法 , 获取值

  6. 封装json

  7. 返回状态码和查看结果

        /// <summary>
        /// XX单个查看
        /// </summary>
        /// <param name="pkey"></param>
        /// <returns></returns>
        /// <remarks>
        /// 1
        /// </remarks>
        [HttpGet("apiName/{pkey}")]
        public IActionResult GetapiName(int pkey)
        {
            try
            {
                if(pkey <= 0)
                {
                    return StatusCode(StatusCodes.Status400BadRequest, UtilHelper.JOutput("404"));
                }
                //实例化TableName对象
                TableName tableName = new TableName();
                //不存在 , 返回错误状态码
                if (!tableName.Exists($"pkey ='{pkey}'"))
                {
                    return StatusCode(StatusCodes.Status400BadRequest, UtilHelper.JOutput("404"));
                }
                //获取值
                tableName.GetModel($"pkey ='{pkey}'");

                //封装为json
                JObject res = new JObject()
                {
                    ["fields1"] = tableName.fields1,
                    ["fields2"] = tableName.fields2.ToString("yyyy-MM-dd HH:mm:ss")//fields2为日期类型

                };
                return StatusCode(StatusCodes.Status200OK, UtilHelper.JOutput("204", res));
            }
            catch (Exception ex)
            {
                return StatusCode(StatusCodes.Status500InternalServerError, UtilHelper.JOutput("50000001"));
            }
        }

9.7 批量查看

        /// <summary>
        /// XX批量查看
        /// </summary>
        /// <param name="limit">指定返回记录的数量</param>
        /// <param name="page">指定返回记录的开始位置</param>
        /// <param name="per_page">指定每页记录数</param>
        /// <param name="sortby">指定排序字段</param>
        /// <param name="order">指定排序方式,asc:正序,desc:倒序</param>
        /// <param name="column">指定查询列,逗号隔开</param>
        /// <param name="search_value">指定模糊查询的内容</param>
        /// <param name="search_column">指定搜索列,逗号隔开</param>
        /// <param name="filter">指定过滤字段,格式为[{"column":"inte_system_tag","value":"1"}]</param>
        /// <param name="time">指定时间筛选的内容,格式为[{"column":"sur_start_time","start":"2020-12-22T23:15:00","end":"2022-12-22T23:20:00"}]</param>
        /// <returns></returns>
        /// <remarks>
        /// 
        /// </remarks>
        [HttpGet("apiName")]
        public IActionResult apiName(int? limit = 0, int? page = 1, int? per_page = 10, string? sortby = "gxsj", string? order = "desc", string? column = "", string? search_column = "", string? search_value = "", string? filter = "[]", string? time = "[]")
        {
            try
            {
                //实例化TableName对象
                TableName tableName = new TableName();

                //调用sql拼接
                JObject sqlObj = ControllerHelper.ConcatSql(limit, page, per_page, sortby, order, column, search_column, search_value, filter, time);
                JArray jArray = baseTcmPulseDiagnosis.JDataTableToList(baseTcmPulseDiagnosis.GetList(column.Replace(",", ","), sqlObj["where"].ToString(), sqlObj["limit"].ToString(), sqlObj["order"].ToString()).Tables[0]);

                //封装json
                JObject res = new JObject()
                {
                    ["list"] = jArray,
                    ["total"] = baseTcmPulseDiagnosis.GetTotal(sqlObj["where"].ToString()),
                };

                return StatusCode(StatusCodes.Status200OK, UtilHelper.JOutput("201", res));

            }
            catch (Exception ex)
            {
                return StatusCode(StatusCodes.Status400BadRequest, UtilHelper.JOutput("50000001");
            }
        }

10. gitee使用

10.1 下载

git下载 : https://git-scm.com/

gui小乌龟(可选软件) : https://tortoisegit.org/download/

10.2 配置

  • 配置RSA公钥

    打开git bash , 一直回车 , 公钥文件会存在 c/user/用户名称/.ssh/id_rsa.pub中

    ssh-keygen -t rsa -C "你的邮箱"

  • 密钥全部复制到gitee网站中

    官网---个人---设置---ssh公钥---下面的公钥文本域

  • 进行基础信息配置

    打开git bash , 输入以下信息

      git config --global user.name "你的名字或昵称" //注意名字一定是网站上@后边的内容
      git config --global user.email "你的邮箱"

10.3 命令

命令

含义

git clone 远程仓库地址

克隆远程仓库到本地

git remote add origin(默认的远程仓库名字) 远程仓库地址

仓库关联

git remote -v

查看关联的远程库信息

git status

查看在你上次提交之后是否有对文件进行再次修改

git add 文件名

将文件添加到本地仓库的提交缓存

git commit -m "注释"

将缓存区内容添加到本地仓库

git push origin master

将本地版本库推送到远程服务器

git pull --rebase origin master

重新拉取

git pull origin master

10.4 上传修改后的文件流程(git)

  • 在修改的文件目录下 , 右键点击 open git bash here

  • git add XX.cs

  • git commit - m "注释"

  • git pull origin master

  • git push origin master

若出现此问题 , 先pull 再push

在这里插入图片描述

10.5 上传修改后的文件流程(可视化)

右键 -> Git 提交(c) ->master

点击提交 -> 推送

若有冲突 , 先拉取 解决冲突 ,再推送

若报错:

git pull报错:error: Your local changes to the following files would be overwritten by merge

方法1:

保留刚才本地修改的代码,并把git服务器上的代码pull到本地(本地刚才修改的代码将会被暂时封存起来)

git stash
git pull origin master
git stash pop

如此一来,服务器上的代码更新到了本地,而且你本地修改的代码也没有被覆盖,之后使用add,commit,push 命令即可更新本地代码到服务器了。

方法2:

完全地覆盖本地的代码,只保留服务器端代码,则直接回退到上一个版本,再进行pull:

git reset --hard
git pull origin master

11 . 技术

11.1 JWT

11.2 RDBC

11.3 消息推送

1. 数据库设计

  • 准备发送的消息(ExtrMsg表)

字段名

类型

长度

是否能为null

注释

msg_id(主键)

int

11

消息编号

msg_titile

varchar

200

消息标题

msg_desc

varchar

500

消息简介

msg_content

text

消息内容

receiver_user_id

int

11

要通知的用户ID

msg_type

varhar

11

消息类型(1-站内信 , 2-邮件 , 3-短信) , 若有多个以逗号隔开

is_read

tinyint

4

是否已读(1-是 , 0-否)

read_time

datetime

阅读时间

is_send_message

tinyint

4

是否发送短信(1-是 , 0-否)

is_send_email

tinyint

4

是否发送邮件(1-是 , 0-否)

created_time

daretime

创建时间

is_send

int

4

是否发送完成

receiver_type

int

11

用户类型(1-人员 , 2-管理员)

template_no

int

11

短信模版

phone_msg

varchar

1000

电话通知

is_delete

int

11

是否删除(1-是 , 0-否)

数据样例

msg_id

msg_titile

msg_desc

msg_content

receiver_user_id

msg_type

is_read

read_time

is_send_message

is_send_email

created_time

is_send

receiver_type

template_no

phone_msg

is_delete

1977

用户资质

用户资质申请提交

超级管理员(administrator)您好,轻狂书生(wsic0070)用户提交了新的用户资质申请,请及时处理。

1

1,2,3

0

0000-00-00 00:00:00

1

1

2024-03-18 16:11:23

1

2

1

{ "name": "超级管理员(administrator)", "user": "轻狂书生(wsic0070)", "type": "用户资质" }

0

  • 日志信息(ExtrMsgLog表)

字段名

类型

长度

是否能为null

注释

msg_log_id(主键)

int

11

消息发送日志编号

msg_id

int

11

消息编号

msg_type

tinyint

4

发送方式(1-短信 , 2-邮件)

msg_address

varchar

300

发送地址(短信即填手机号 , 邮件即填邮箱号)

msg_time

datetime

发送时间

msg_result

int

11

发送结果(1-成功 , 0-失败)

2.代码思想

  • 读取 ExtrMsg 表 , 找到待发送且未被删除的所有消息 (以JArray来存储)

  • foreach循环遍历JArray数组(即每一遍循环 , 处理一条消息)

  • 获取一条消息中的所有字段值 , 对 msg_type 字段值进行判断处理(短信发送和邮箱发送两种情况)

  • 要做好对 ExtrMsgLog 表的处理 , 发送成功与否 , 都需要进行记录

11.4 华为云API

1.认证鉴权 (https://support.huaweicloud.com/intl/zh-cn/api-workspace/workspace_09_0010.html)

  • Token认证:通过Token认证调用请求。

  • AK/SK认证:通过AK(Access Key ID)/SK(Secret Access Key)加密调用请求。