千家信息网

如何利用ASP.NET MVC+EasyUI+SqlServer搭建企业开发框架

发表于:2025-02-04 作者:千家信息网编辑
千家信息网最后更新 2025年02月04日,这篇文章将为大家详细讲解有关如何利用ASP.NET MVC+EasyUI+SqlServer搭建企业开发框架,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。我们要搭建
千家信息网最后更新 2025年02月04日如何利用ASP.NET MVC+EasyUI+SqlServer搭建企业开发框架

这篇文章将为大家详细讲解有关如何利用ASP.NET MVC+EasyUI+SqlServer搭建企业开发框架,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

我们要搭建的框架是企业级开发框架,适用用企业管理信息系统的开发,如:OA、HR等

1、框架名称:sampleFrame。

2、搭建原则:最少知识原则。

3、先定义一个简单的编码规范:除类名和接口名外,其余首字母小写。

4、准备开发环境:vs2010及以上(mvc4)、sqlserver、jquery2.0和easyui1.4.5

首先来看一下列表页面的效果图:

我们期望简洁带前台代码,如下:

customerId companyName phone address

为了这样简洁的前台,我们需要准备:

1、通用的布局模板_Layout.cshtml。base.css、base.js、defaultSettings.js、tool.js和private.js见后面

               @RenderSection("scripts", required: false) @RenderBody()

2、平台样式表base.css

.icon-find{ background: url('icons/find.png') no-repeat center center;}.datagrid-toolbar div:nth-child(1){ float: left; width: 60%;}.datagrid-toolbar div:nth-child(2){ margin-left: 60%; margin-right: 10px; width: auto; text-align: right;}

3、基本方法脚本base.js

//取消自动渲染$.parser.auto = false;function pageInit() { //改变控件默认值 $.fn.linkbutton.defaults.plain = true; $.fn.datagrid.defaults.fit = true; $.fn.datagrid.defaults.fitColumns = true; $.fn.datagrid.defaults.pagination = true; //显示ajax异常信息 $(document).ajaxError(function (event, xhr, options, exc) { $.messager.alert({ title: '异步请求出错', msg: xhr.responseText, icon: "error" }); }); //地址栏传参允许中文 jQuery(document).ajaxSend(function (event, request, options) { options.url = encodeURI(options.url); }); $.parser.parse();}function loadList(settings) { var settings = $.extend(true, {}, loadListDefaultSettings, settings); if ($("#" + settings.gridId).length == 0) $.messager.alert({ title: "系统异常", msg: "DataGrid:" + settings.gridId + "不存在!", icon: "error" }); var quickQueryData = []; if ($("#" + settings.queryBoxId).length > 0) { var val = $("#" + settings.queryBoxId).textbox("getValue"); if (settings.searchFields && val) {  var keys = settings.searchFields.split(',');  for (i = 0, len = keys.length; i < len; i++) {  quickQueryData.push({ field: keys[i], method: 'inLike', value: val });  } } } var queryData = []; //详细查询预留  //加载数据 $("#" + settings.gridId).datagrid("load", { quickQueryData: JSON.stringify(quickQueryData), queryData: JSON.stringify(queryData) });}

4、基本脚本默认值defaultSettings.js

//查询参数设置var loadListDefaultSettings = { url: "getList", gridId: "dataGrid", queryWindowId: "queryWindow", queryBoxId: "queryBox", searchFields: "Name", addQueryString: true, prompt: "请输入"};5、可能需要使用的工具方法tool.js//判断是否包含地址栏参数function hasQueryString(key, url) { if (typeof (url) == "undefined") url = _window.location.search; var re = new RegExp("[?&]" + key + "=([^\\&]*)", "i"); var a = re.exec(url); if (a == null) return false; return true;}//获取地址栏参数,如果参数不存在则返回空字符串function getQueryString(key, url) { if (typeof (url) == "undefined") url = _window.location.search; var re = new RegExp("[?&]" + key + "=([^\\&]*)", "i"); var a = re.exec(url); if (a == null) return ""; return a[1];}//将当前地址栏参数加入到urlfunction addUrlSearch(url) { var newParams = []; var paramKeys = _window.location.search.replace('?', '').split('&'); for (var i = 0; i < paramKeys.length; i++) { var key = paramKeys[i].split('=')[0]; if (key == "" || key == "_t" || key == "_winid" || key == "isTab")  continue; if (!hasQueryString(key, url))  newParams.push(paramKeys[i]); } if (url.indexOf('?') >= 0) return url + "&" + newParams.join('&'); else return url + "?" + newParams.join('&');}//url增加参数function addSearch(url, key, value) { if (!hasQueryString(key, url)) { if (url.indexOf('?') >= 0)  return url + "&" + key + "=" + value; else  return url + "?" + key + "=" + value; } else return url;}//获取数组中对象的某个值,逗号分隔function getValues(rows, attr) { var fieldValues = []; for (var i = 0; i < rows.length; i++) { if (rows[i] != null)  fieldValues.push(rows[i][attr]); } return fieldValues.join(',');}

6、可能需要使用的私有方法private.js,此文件包含的方法专供base.js使用,开发web时禁止使用

//替换掉Url中的{}参数function replaceUrl(settings, pty) { if (!pty) pty = "url"; if (!settings[pty]) return; var str = settings[pty]; var guid = ""; var result = str.replace(/\{[0-9a-zA-Z_]*\}/g, function (e) { var key = e.substring(1, e.length - 1); if (key == "GUID") {  if (!guid) {  $.ajax({   url: "getGuid",   type: "post",   async: false,   success: function (text, textStatus) {   guid = text;   }  });  }  return guid; } if (hasQueryString(key)) //从地址栏返回  return getQueryString(key); if (settings.currentRow && settings.currentRow[key])//从当前行返回  return settings.currentRow[key]; if (settings.paramFrom) { //从指定控件返回  var ctrl = mini.get(settings.paramFrom);  if (ctrl == undefined) {  $.messager.alert({ title: 'UI出错', msg: "Id为" + settings.paramFrom + "的控件不存在!", icon: "error" });    return;  }  else if (ctrl.showCheckBox) {  return getValues(ctrl.getCheckedNodes(), key);  }  else if (ctrl.getSelecteds)  return getValues(ctrl.getSelecteds(), key);  else if (ctrl.getValue)  return ctrl.getValue(); } return e; }); settings[pty] = result; return result;}//转化为全路径function changeToFullUrl(settings) { var url = settings.url; if (url.indexOf('/') == 0 || url.indexOf("http://") == 0 || url.indexOf('?') == 0 || url == "") return url; currentUrlPathName = _window.location.pathname; var currentPathNameParts = currentUrlPathName.split('/'); var pathNameParts = url.split('?')[0].split('/'); if (currentPathNameParts[currentPathNameParts.length - 1] == "") currentPathNameParts.pop(); //去掉一个反斜线 if (pathNameParts[pathNameParts.length - 1] == "") pathNameParts.pop(); //去掉一个反斜线 var index = currentPathNameParts.length - 1; for (var i = 0; i < pathNameParts.length; i++) { if (pathNameParts[i] == "..") {  index = index - 1;  if (index <= 0) {  $.messager.alert({ title: "系统异常", msg: "Url错误:" + url + "!", icon: "error" });return;  }  continue; } if (index < currentPathNameParts.length)  currentPathNameParts[index] = pathNameParts[i]; else  currentPathNameParts.push(pathNameParts[i]); index = index + 1; } var length = currentPathNameParts.length; for (var i = index; i < length; i++) { currentPathNameParts.pop(); } var result = currentPathNameParts.join('/'); if (url.indexOf('?') > 0) result += url.substring(url.indexOf('?')); settings.url = result;}

我们期望简洁的后台代码,如下:

using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Mvc;using formula;using System.Data;namespace demo.Areas.basic.Controllers{ public class customerController : BaseController { public JsonResult getList(QueryBuilder qb) {  SqlHelper sqlHelper = new SqlHelper("demo");  var data = sqlHelper.ExecuteGridData("select *,id=customerId from customer", qb);  return Json(data); } }}

为了这种简洁的代码我们需要:

1、Controller基类BaseController:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Web.Mvc;using System.Data.Entity;using System.Data.SqlClient;using System.Data.Entity.Validation;using System.ComponentModel;using System.Reflection;using System.Web.Security;using formula;namespace formula{ public abstract class BaseController : Controller { #region 处理不存在的Action protected override void HandleUnknownAction(string actionName) {  if (Request.HttpMethod == "POST")  {  HttpContext.ClearError();  HttpContext.Response.Clear();  HttpContext.Response.StatusCode = 500;  HttpContext.Response.Write("没有Action:" + actionName);  HttpContext.Response.End();  }  // 搜索文件是否存在  var filePath = "";  if (RouteData.DataTokens["area"] != null)  filePath = string.Format("~/Areas/{2}/Views/{1}/{0}.cshtml", actionName, RouteData.Values["controller"], RouteData.DataTokens["area"]);  else  filePath = string.Format("~/Views/{1}/{0}.cshtml", actionName, RouteData.Values["controller"]);  if (System.IO.File.Exists(Server.MapPath(filePath)))  {  View(filePath).ExecuteResult(ControllerContext);  }  else  {  HttpContext.ClearError();  HttpContext.Response.Clear();  HttpContext.Response.StatusCode = 500;  HttpContext.Response.Write("没有Action:" + actionName);  HttpContext.Response.End();  } } #endregion #region 基类Json方法重载 protected override JsonResult Json(object data, string contentType, Encoding contentEncoding, JsonRequestBehavior behavior) {  NewtonJsonResult result = new NewtonJsonResult() { Data = data, ContentType = contentType, ContentEncoding = contentEncoding, JsonRequestBehavior = behavior };  return result; } protected override JsonResult Json(object data, string contentType, Encoding contentEncoding) {  NewtonJsonResult result = new NewtonJsonResult() { Data = data, ContentType = contentType, ContentEncoding = contentEncoding };  return result; } #endregion #region 异常处理 protected override void OnException(ExceptionContext filterContext) {  Exception exp = filterContext.Exception;  if (string.IsNullOrEmpty(exp.Message))  exp = exp.GetBaseException();  if (filterContext.RequestContext.HttpContext.Request.IsAjaxRequest())  {  var response = filterContext.RequestContext.HttpContext.Response;  response.Clear();  response.Write(exp.Message);  response.StatusCode = 500;  response.End();  } } #endregion }}

2、查询构造器QueryBuilder:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Collections;using System.Web.Mvc;namespace formula{ [ModelBinder(typeof(QueryBuilderBinder))] public class QueryBuilder : SearchCondition { public int page { get; set; } public int rows { get; set; } public string sort { get; set; } public string order { get; set; } public int total { get; set; } public string getOrderByString(bool hasOrderBy = true) {  var sortFields = this.sort.Split(',');  var sortOrders = this.order.Split(',');  string str = "";  for (int i = 0; i < sortFields.Length; i++)  {  str += sortFields[i] + " " + sortOrders[i] + ",";  }  if (hasOrderBy && str != "")  str = "order by " + str;  return str.Trim(','); } } public class SearchCondition { public string fields = "*"; private List quickItems = new List(); private List complexItems = new List(); public SearchCondition add(string field, string method, object val, bool isQuickSearch = false) {  //处理日期型数据  if (method == "<" || method == "<=")  {  if (val.GetType() == typeof(DateTime))  {   DateTime t = (DateTime)val;   val = t.Date.AddHours(23).AddMinutes(59).AddSeconds(59);  }  }  ConditionItem item = new ConditionItem(field, method, val);  if (isQuickSearch)  quickItems.Add(item);  else  complexItems.Add(item);  return this; } public string getWhereString(bool hasWhere = true) {  if (quickItems.Count == 0 && complexItems.Count == 0)  return "";  string strWhere = "";  if (quickItems.Count > 0)  strWhere += " and (" + getGourpWhereString(quickItems, true) + ")";  if (complexItems.Count > 0)  strWhere += " and (" + getGourpWhereString(complexItems, false) + ")";  if (hasWhere)  strWhere = " where " + strWhere.Substring(4);  else  strWhere = " and " + strWhere.Substring(4);  return strWhere; } #region 私有方法 private string getGourpWhereString(List list, bool isOrRelation = false) {  if (list.Count == 0)  return "";  string strWhere = "";  for (int i = 0; i < list.Count(); i++)  {  var item = list[i];  string str = item.getWhereString();  if (isOrRelation)  {   strWhere += " or " + str;  }  else  {   strWhere += " and " + str;  }  }  strWhere = strWhere.Substring(4);  return strWhere; } #endregion } public class ConditionItem { public ConditionItem(string field, string method, object val) {  this.field = field;  this.method = method;  this.value = val; } public string field { get; set; } public string method { get; set; } public object value { get; set; } public string getWhereString() {  var item = this;  switch (item.method)  {  case "=":  case "<":  case ">":  case "<=":  case ">=":  case "<>":   return string.Format("{0} {1} '{2}'", item.field, item.method, item.value);  case "in":   string v = "";   if (item.value is ICollection)   {   ICollection collection = item.value as ICollection;   v = string.Join("','", collection.ToArray());   return string.Format("{0} in('{1}')", item.field, v);   }   else   {   v = item.value.ToString().Replace(",", "','");   }   return string.Format("{0} in ('{1}')", item.field, v);  case "between":   object[] objs = item.value as object[];   return string.Format("{0} between '{1}' and '{2}'", item.field, objs[0], objs[1]);  case "inLike":   string[] arr = null;   if (item.value is ICollection)   {   ICollection collection = item.value as ICollection;   arr = collection.ToArray();   }   else   {   arr = item.value.ToString().Split(',', ',');   }   string str = "";   foreach (string s in arr)   {   str += string.Format("or {0} like '%{1}%'", item.field, s);   }   return "(" + str.Substring(3) + ")";  case "day":   DateTime dt = DateTime.Now;   if (!DateTime.TryParse(item.value.ToString(), out dt))   {   throw new BuessinessException("查询条件不能转化为日期时间");   }   string start = dt.Date.ToString("yyyy-MM-dd");   string end = dt.Date.AddDays(1).ToString("yyyy-MM-dd");   return string.Format("{0} between '{1}' and '{2}'", item.field, start, end);  case "startWith":   return string.Format("{0} like '{1}%'", item.field, item.value);  case "endWith":   return string.Format("{0} like '%{1}'", item.field, item.value);  default:   return "";  } } }}

3、查询构造器QueryBuilder的创建方法QueryBuilderBinder:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Web.Mvc;namespace formula{ public class QueryBuilderBinder : IModelBinder { public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) {  var qb = (QueryBuilder)(bindingContext.Model ?? new QueryBuilder());  var dict = controllerContext.HttpContext.Request.Params;  var quickQueryList = !string.IsNullOrEmpty(dict["quickQueryData"]) ? JsonHelper.ToList(dict["quickQueryData"]) : new List>();  var queryList = !string.IsNullOrEmpty(dict["queryData"]) ? JsonHelper.ToList(dict["queryData"]) : new List>();  foreach (var dic in quickQueryList)  {  var val = dic["value"].ToString();  if (val == "") continue;  qb.add(dic["field"].ToString(), dic["method"].ToString(), val, true);  }  foreach (var dic in queryList)  {  var val = dic["value"].ToString();  if (val == "") continue;  qb.add(dic["field"].ToString(), dic["method"].ToString(), val, false);  }   qb.page = !string.IsNullOrEmpty(dict["page"]) ? int.Parse(dict["page"].ToString()) : 1;  qb.rows = !string.IsNullOrEmpty(dict["rows"]) ? int.Parse(dict["rows"].ToString()) : 10;  qb.sort = !string.IsNullOrEmpty(dict["sort"]) ? dict["page"].ToString() : "id";  qb.order = !string.IsNullOrEmpty(dict["order"]) ? dict["order"].ToString() : "desc";  return qb; } }}

4、数据库查询帮助类SqlHelper:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Data.SqlClient;using System.Data;using System.Web;namespace formula{ public class SqlHelper { #region 构造函数 public SqlHelper(string connName) {  if (System.Configuration.ConfigurationManager.ConnectionStrings[connName] == null)  throw new BuessinessException(string.Format("配置文件中不包含数据库连接字符串:{0}", connName));  this.connName = connName;  this.connString = System.Configuration.ConfigurationManager.ConnectionStrings[connName].ConnectionString; } public string connName { get; private set; } public string connString { get; private set; } public string dbName {  get  {  SqlConnection conn = new SqlConnection(connString);  return conn.Database;  } } #endregion #region 基本方法 public object ExecuteScalar(string cmdText) {  using (SqlConnection conn = new SqlConnection(connString))  {  conn.Open();  SqlCommand cmd = new SqlCommand(cmdText, conn);  return cmd.ExecuteScalar();    } } public DataTable ExecuteDataTable(string cmdText) {  using (SqlConnection conn = new SqlConnection(connString))  {  DataTable dt = new DataTable();  SqlDataAdapter apt = new SqlDataAdapter(cmdText, conn);  apt.Fill(dt);  return dt;  } } public DataTable ExecuteDataTable(string cmdText, int start, int len) {  using (SqlConnection conn = new SqlConnection(connString))  {  DataTable dt = new DataTable();  SqlDataAdapter apt = new SqlDataAdapter(cmdText, conn);  apt.Fill(start, len, dt);  return dt;  } } public string ExecuteNonQuery(string cmdText) {  using (SqlConnection conn = new SqlConnection(connString))  {  conn.Open();  SqlCommand cmd = new SqlCommand(cmdText, conn);  return cmd.ExecuteNonQuery().ToString();  } } #endregion #region 支持查询对象 public DataTable ExecuteDataTable(string sql, SearchCondition cnd, string orderBy) {  string sqlWhere = " where 1=1" + GetUrlFilterSqlWhere(sql) + cnd.getWhereString(false);  sql = string.Format("select {0} from ({1}) sourceTable {2} {3}", cnd.fields, sql, sqlWhere, orderBy);  DataTable dt = this.ExecuteDataTable(sql);  return dt; } public Dictionary ExecuteGridData(string sql, QueryBuilder qb) {  string sqlWhere = " where 1=1" + GetUrlFilterSqlWhere(sql) + qb.getWhereString(false);  qb.total = (int)this.ExecuteScalar(string.Format("select count(1) from ({0}) sourceTable {1}", sql, sqlWhere));  sql = string.Format("select {0} from ({1}) sourceTable {2} {3}", qb.fields, sql, sqlWhere, qb.getOrderByString());  DataTable dt = ExecuteDataTable(sql, (qb.page - 1) * qb.rows, qb.rows);  Dictionary dic = new Dictionary();  dic.Add("total", qb.total);  dic.Add("rows", dt);    return dic; } #endregion #region 私有方法 private string GetUrlFilterSqlWhere(string sql) {  sql = string.Format("select * from({0}) as dt1 where 1=2", sql);  var dtField = ExecuteDataTable(sql);  StringBuilder sb = new StringBuilder();  foreach (string key in HttpContext.Current.Request.QueryString.Keys)  {  if (string.IsNullOrEmpty(key) || key.ToLower() == "id")   continue;  if (dtField.Columns.Contains(key))  {   string value = HttpContext.Current.Server.UrlDecode(HttpContext.Current.Request[key]);   value = value.Replace(",", "','");   sb.AppendFormat(" and {0} in ('{1}')", key, value);  }  }  return sb.ToString(); } #endregion }}

5、用于取代返回值JsonResult的NewtonJsonResult:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Web.Mvc;using System.Web;using System.Data;namespace formula{ public class NewtonJsonResult : JsonResult { public override void ExecuteResult(ControllerContext context) {  //确认是否用于响应HTTP-Get请求  if (this.JsonRequestBehavior == JsonRequestBehavior.DenyGet &&  string.Compare(context.HttpContext.Request.HttpMethod, "GET", true) == 0)  {  throw new InvalidOperationException("禁止Get请求");  }  HttpResponseBase response = context.HttpContext.Response;  //设置媒体类型和编码方式  response.ContentType = string.IsNullOrEmpty(this.ContentType) ?  "application/json" : this.ContentType;  if (this.ContentEncoding != null)  {  response.ContentEncoding = this.ContentEncoding;  }  //序列化对象,并写入当前的HttpResponse  if (null == this.Data) return;  if (this.Data is string)  {  response.Write(Data);  }  else if (this.Data is DataRow)  {  Dictionary dic = new Dictionary();  DataRow row = this.Data as DataRow;  foreach (DataColumn col in row.Table.Columns)  {   dic.Add(col.ColumnName, row[col]);  }  response.Write(JsonHelper.ToJson(dic));  }  else  {  response.Write(JsonHelper.ToJson(this.Data));  } } }}

6、Json序列化和反序列的帮助类JsonHelper:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using Newtonsoft.Json.Converters;using Newtonsoft.Json;namespace formula{ public static class JsonHelper { public static string ToJson(T obj) {  if (obj == null || obj.ToString() == "null") return null;  if (obj != null && (obj.GetType() == typeof(String) || obj.GetType() == typeof(string)))  {  return obj.ToString();  }  IsoDateTimeConverter dt = new IsoDateTimeConverter();  dt.DateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss";  return JsonConvert.SerializeObject(obj, dt); } ///   /// 从一个Json串生成对象信息  ///   /// JSON字符串  /// 对象类型   ///   public static T ToObject(string json) where T : class {  if (String.IsNullOrEmpty(json)) return null;  T obj = JsonConvert.DeserializeObject(json);  return obj; } ///  /// 返回 Diction ///  ///  ///  public static Dictionary ToObject(string json) {  if (String.IsNullOrEmpty(json)) return new Dictionary();  return ToObject>(json); } ///  /// 返回 List> ///  ///  ///  public static List> ToList(string json) {  if (String.IsNullOrEmpty(json)) return new List>();  return ToObject>>(json); } ///  /// 组装对象 ///  ///  ///  public static void PopulateObject(string json, object obj) {  if (String.IsNullOrEmpty(json)) return;  JsonConvert.PopulateObject(json, obj); } }}

7、用于区分系统异常和业务异常的BusinessException:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Runtime.Serialization;namespace formula{ ///  /// 业务异常 ///   [Serializable] public class BuessinessException : Exception { ///  /// 系统异常构造函数 ///  public BuessinessException() { } ///  /// 系统异常构造函数 ///  /// 异常的消息 public BuessinessException(string message)  : base(message) { } ///  /// 系统异常构造函数 ///  /// 异常的消息 /// 内部的异常 public BuessinessException(string message, System.Exception inner)  : base(message, inner) { } ///  /// 系统异常构造函数 ///  /// 存有有关所引发异常的序列化的对象数据 /// 包含有关源或目标的上下文信息 public BuessinessException(SerializationInfo info, StreamingContext context)  : base(info, context) { } }}

关于"如何利用ASP.NET MVC+EasyUI+SqlServer搭建企业开发框架"这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

方法 系统 查询 参数 对象 开发 框架 函数 地址 数据 企业 简洁 信息 序列 代码 控件 文件 篇文章 处理 帮助 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 后台服务器如何管理网站 联想电脑网络安全模式下如何联网 江苏网络技术服务咨询报价 数据库怎样查询表信息 腾讯云服务器安全系统下载 华夏云城网络技术有限公司 企业怎么选择云服务器 中国互联网公司黑科技 软件开发技术自学网站 宁德时代软件开发工程师待遇 深圳中小软件开发公司 网络安全竖着画手抄报 阿里云polar数据库认证招聘 数据库运行速度怎样描述 apex服务器换不了 吃鸡更新后进不去服务器 科技互联网教育产品 网警检查网络安全检查出的问题 互联网科技核心期刊 网络安全硕士就业 网络安全的屏保图片 美亚柏科网络安全事业部 网络安全手抄报中学生八开 数据采集系统 数据库 华为服务器管理口怎么进去 服务器win2008重启命令 上海聆客网络技术 乐清市秋瑞软件开发有限公司 sql数据库错误怎么看 网络安全法对公司上市有影响么
0