-之动态查询,查询逻辑封装复用

基于领域驱动设计(DDD)超轻量级快速开发架构详细介绍请看

https://www.cnblogs.com/neozhu/p/13174234.html

需求

  1. 配合EasyUI datagird filter实现多字段(任意字段)的筛选
  2. 根据业务需求筛选特定的状态或条件,如:查看结案的订单,最近30天的订单,查看属于我的订单.等等,这些逻辑是固定也是可以被重用,但又不想每次写相同的条件,那么下面我会给我的解决方案.

需求1只是一个偷懒的实现方式,因为datagrid自带这个功能,但又不想根据具体的需求来画查询条件,如果需求必须要再datagrid上面做一块查询条件的输入那目前只能在前端自己手工添加,在组织后传入后台,暂时不在这里讨论

需求2可能不太好解释,看完代码就自然理解为什么要这么做了,这么做的好处有哪些

具体实现的方式

默认情况下 datagrid 有几列就可以对这几列进行筛选,对于日期型的字段会采用between,选择2个时间之间进行筛选,数字类型会提供大于小于等符号选择,可以自行尝试,其原理是datagrid 会根据datagrid 头部输入的值生成一个Json字符串发送后台请求数据

JSON:格式

filterRules: [
{field:field,op:op,value:value},
{field:field,op:op,value:value},
] 
  • 通常的做法是一个一个判断加条件

 var filters = JsonConvert.DeserializeObject<IEnumerable<filterRule>>(filterRules);
foreach (var rule in filters)
{
if (rule.field == "Id" && !string.IsNullOrEmpty(rule.value) && rule.value.IsInt())
{
var val = Convert.ToInt32(rule.value);
switch (rule.op)
{
case "equal":
this.And(x => x.Id == val);
break;
case "notequal":
this.And(x => x.Id != val);
break;
case "less":
this.And(x => x.Id < val);
break;
case "lessorequal":
this.And(x => x.Id <= val);
break;
case "greater":
this.And(x => x.Id > val);
break;
case "greaterorequal":
this.And(x => x.Id >= val);
break;
default:
this.And(x => x.Id == val);
break;
}
}
if (rule.field == "Name" && !string.IsNullOrEmpty(rule.value))
{
this.And(x => x.Name.Contains(rule.value));
}
if (rule.field == "Code" && !string.IsNullOrEmpty(rule.value))
{
this.And(x => x.Code.Contains(rule.value));
} if (rule.field == "Address" && !string.IsNullOrEmpty(rule.value))
{
this.And(x => x.Address.Contains(rule.value));
} if (rule.field == "Contect" && !string.IsNullOrEmpty(rule.value))
{
this.And(x => x.Contect.Contains(rule.value));
} if (rule.field == "PhoneNumber" && !string.IsNullOrEmpty(rule.value))
{
this.And(x => x.PhoneNumber.Contains(rule.value));
} if (rule.field == "RegisterDate" && !string.IsNullOrEmpty(rule.value))
{
if (rule.op == "between")
{
var datearray = rule.value.Split(new char[] { '-' });
var start = Convert.ToDateTime(datearray[]);
var end = Convert.ToDateTime(datearray[]); this.And(x => SqlFunctions.DateDiff("d", start, x.RegisterDate) >= );
this.And(x => SqlFunctions.DateDiff("d", end, x.RegisterDate) <= );
}
}
if (rule.field == "CreatedDate" && !string.IsNullOrEmpty(rule.value))
{
if (rule.op == "between")
{
var datearray = rule.value.Split(new char[] { '-' });
var start = Convert.ToDateTime(datearray[]);
var end = Convert.ToDateTime(datearray[]); this.And(x => SqlFunctions.DateDiff("d", start, x.CreatedDate) >= );
this.And(x => SqlFunctions.DateDiff("d", end, x.CreatedDate) <= );
}
} if (rule.field == "CreatedBy" && !string.IsNullOrEmpty(rule.value))
{
this.And(x => x.CreatedBy.Contains(rule.value));
} if (rule.field == "LastModifiedDate" && !string.IsNullOrEmpty(rule.value))
{
if (rule.op == "between")
{
var datearray = rule.value.Split(new char[] { '-' });
var start = Convert.ToDateTime(datearray[]);
var end = Convert.ToDateTime(datearray[]); this.And(x => SqlFunctions.DateDiff("d", start, x.LastModifiedDate) >= );
this.And(x => SqlFunctions.DateDiff("d", end, x.LastModifiedDate) <= );
}
} if (rule.field == "LastModifiedBy" && !string.IsNullOrEmpty(rule.value))
{
this.And(x => x.LastModifiedBy.Contains(rule.value));
} }
  • 新的做法是动态根据field,op,value生成一个linq 表达式,不用再做繁琐的判断,这块代码也可以被其它项目使用,非常好用

namespace SmartAdmin
{ public static class PredicateBuilder
{ public static Expression<Func<T, bool>> FromFilter<T>(string filtergroup) {
Expression<Func<T, bool>> any = x => true;
if (!string.IsNullOrEmpty(filtergroup))
{
var filters = JsonSerializer.Deserialize<filter[]>(filtergroup); foreach (var filter in filters)
{
if (Enum.TryParse(filter.op, out OperationExpression op) && !string.IsNullOrEmpty(filter.value))
{
var expression = GetCriteriaWhere<T>(filter.field, op, filter.value);
any = any.And(expression);
}
}
} return any;
} #region -- Public methods --
public static Expression<Func<T, bool>> GetCriteriaWhere<T>(Expression<Func<T, object>> e, OperationExpression selectedOperator, object fieldValue)
{
var name = GetOperand<T>(e);
return GetCriteriaWhere<T>(name, selectedOperator, fieldValue);
} public static Expression<Func<T, bool>> GetCriteriaWhere<T, T2>(Expression<Func<T, object>> e, OperationExpression selectedOperator, object fieldValue)
{
var name = GetOperand<T>(e);
return GetCriteriaWhere<T, T2>(name, selectedOperator, fieldValue);
} public static Expression<Func<T, bool>> GetCriteriaWhere<T>(string fieldName, OperationExpression selectedOperator, object fieldValue)
{
var props = TypeDescriptor.GetProperties(typeof(T));
var prop = GetProperty(props, fieldName, true);
var parameter = Expression.Parameter(typeof(T));
var expressionParameter = GetMemberExpression<T>(parameter, fieldName);
if (prop != null && fieldValue != null)
{ BinaryExpression body = null;
switch (selectedOperator)
{
case OperationExpression.equal:
body = Expression.Equal(expressionParameter, Expression.Constant(Convert.ChangeType(fieldValue, Nullable.GetUnderlyingType(prop.PropertyType)?? prop.PropertyType), prop.PropertyType));
return Expression.Lambda<Func<T, bool>>(body, parameter);
case OperationExpression.notequal:
body = Expression.NotEqual(expressionParameter, Expression.Constant(Convert.ChangeType(fieldValue, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType), prop.PropertyType));
return Expression.Lambda<Func<T, bool>>(body, parameter);
case OperationExpression.less:
body = Expression.LessThan(expressionParameter, Expression.Constant(Convert.ChangeType(fieldValue, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType), prop.PropertyType));
return Expression.Lambda<Func<T, bool>>(body, parameter);
case OperationExpression.lessorequal:
body = Expression.LessThanOrEqual(expressionParameter, Expression.Constant(Convert.ChangeType(fieldValue, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType), prop.PropertyType));
return Expression.Lambda<Func<T, bool>>(body, parameter);
case OperationExpression.greater:
body = Expression.GreaterThan(expressionParameter, Expression.Constant(Convert.ChangeType(fieldValue, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType), prop.PropertyType));
return Expression.Lambda<Func<T, bool>>(body, parameter);
case OperationExpression.greaterorequal:
body = Expression.GreaterThanOrEqual(expressionParameter, Expression.Constant(Convert.ChangeType(fieldValue, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType), prop.PropertyType));
return Expression.Lambda<Func<T, bool>>(body, parameter);
case OperationExpression.contains:
var contains = typeof(string).GetMethod("Contains", new[] { typeof(string) });
var bodyLike = Expression.Call(expressionParameter, contains, Expression.Constant(Convert.ChangeType(fieldValue, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType), prop.PropertyType));
return Expression.Lambda<Func<T, bool>>(bodyLike, parameter);
case OperationExpression.endwith:
var endswith = typeof(string).GetMethod("EndsWith",new[] { typeof(string) });
var bodyendwith = Expression.Call(expressionParameter, endswith, Expression.Constant(Convert.ChangeType(fieldValue, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType), prop.PropertyType));
return Expression.Lambda<Func<T, bool>>(bodyendwith, parameter);
case OperationExpression.beginwith:
var startswith = typeof(string).GetMethod("StartsWith", new[] { typeof(string) });
var bodystartswith = Expression.Call(expressionParameter, startswith, Expression.Constant(Convert.ChangeType(fieldValue, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType), prop.PropertyType));
return Expression.Lambda<Func<T, bool>>(bodystartswith, parameter);
case OperationExpression.includes:
return Includes<T>(fieldValue, parameter, expressionParameter, prop.PropertyType);
case OperationExpression.between:
return Between<T>(fieldValue, parameter, expressionParameter, prop.PropertyType);
default:
throw new Exception("Not implement Operation");
}
}
else
{
Expression<Func<T, bool>> filter = x => true;
return filter;
}
} public static Expression<Func<T, bool>> GetCriteriaWhere<T, T2>(string fieldName, OperationExpression selectedOperator, object fieldValue)
{ var props = TypeDescriptor.GetProperties(typeof(T));
var prop = GetProperty(props, fieldName, true); var parameter = Expression.Parameter(typeof(T));
var expressionParameter = GetMemberExpression<T>(parameter, fieldName); if (prop != null && fieldValue != null)
{
switch (selectedOperator)
{
case OperationExpression.any:
return Any<T, T2>(fieldValue, parameter, expressionParameter); default:
throw new Exception("Not implement Operation");
}
}
else
{
Expression<Func<T, bool>> filter = x => true;
return filter;
}
} public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr, Expression<Func<T, bool>> or)
{
if (expr == null)
{
return or;
} return Expression.Lambda<Func<T, bool>>(Expression.OrElse(new SwapVisitor(expr.Parameters[], or.Parameters[]).Visit(expr.Body), or.Body), or.Parameters);
} public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr, Expression<Func<T, bool>> and)
{
if (expr == null)
{
return and;
} return Expression.Lambda<Func<T, bool>>(Expression.AndAlso(new SwapVisitor(expr.Parameters[], and.Parameters[]).Visit(expr.Body), and.Body), and.Parameters);
} #endregion
#region -- Private methods -- private static string GetOperand<T>(Expression<Func<T, object>> exp)
{
if (!( exp.Body is MemberExpression body ))
{
var ubody = (UnaryExpression)exp.Body;
body = ubody.Operand as MemberExpression;
} var operand = body.ToString(); return operand.Substring(); } private static MemberExpression GetMemberExpression<T>(ParameterExpression parameter, string propName)
{
if (string.IsNullOrEmpty(propName))
{
return null;
} var propertiesName = propName.Split('.');
if (propertiesName.Count() == )
{
return Expression.Property(Expression.Property(parameter, propertiesName[]), propertiesName[]);
} return Expression.Property(parameter, propName);
} private static Expression<Func<T, bool>> Includes<T>(object fieldValue, ParameterExpression parameterExpression, MemberExpression memberExpression ,Type type)
{
var safetype= Nullable.GetUnderlyingType(type) ?? type; switch (safetype.Name.ToLower())
{
case "string":
var strlist = (IEnumerable<string>)fieldValue;
if (strlist == null || strlist.Count() == )
{
return x => true;
}
var strmethod = typeof(List<string>).GetMethod("Contains", new Type[] { typeof(string) });
var strcallexp = Expression.Call(Expression.Constant(strlist.ToList()), strmethod, memberExpression);
return Expression.Lambda<Func<T, bool>>(strcallexp, parameterExpression);
case "int32":
var intlist = (IEnumerable<int>)fieldValue;
if (intlist == null || intlist.Count() == )
{
return x => true;
}
var intmethod = typeof(List<int>).GetMethod("Contains", new Type[] { typeof(int) });
var intcallexp = Expression.Call(Expression.Constant(intlist.ToList()), intmethod, memberExpression);
return Expression.Lambda<Func<T, bool>>(intcallexp, parameterExpression);
case "float":
var floatlist = (IEnumerable<float>)fieldValue;
if (floatlist == null || floatlist.Count() == )
{
return x => true;
}
var floatmethod = typeof(List<int>).GetMethod("Contains", new Type[] { typeof(int) });
var floatcallexp = Expression.Call(Expression.Constant(floatlist.ToList()), floatmethod, memberExpression);
return Expression.Lambda<Func<T, bool>>(floatcallexp, parameterExpression);
default:
return x => true;
} }
private static Expression<Func<T, bool>> Between<T>(object fieldValue, ParameterExpression parameterExpression, MemberExpression memberExpression, Type type)
{ var safetype = Nullable.GetUnderlyingType(type) ?? type;
switch (safetype.Name.ToLower())
{
case "datetime":
var datearray = ( (string)fieldValue ).Split(new char[] { '-' }, StringSplitOptions.RemoveEmptyEntries);
var start = Convert.ToDateTime(datearray[] + " 00:00:00", CultureInfo.CurrentCulture);
var end = Convert.ToDateTime(datearray[] + " 23:59:59", CultureInfo.CurrentCulture);
var greater = Expression.GreaterThan(memberExpression, Expression.Constant(start, type));
var less = Expression.LessThan(memberExpression, Expression.Constant(end, type));
return Expression.Lambda<Func<T, bool>>(greater, parameterExpression)
.And(Expression.Lambda<Func<T, bool>>(less, parameterExpression));
case "int":
case "int32":
var intarray = ( (string)fieldValue ).Split(new char[] { '-' }, StringSplitOptions.RemoveEmptyEntries);
var min = Convert.ToInt32(intarray[] , CultureInfo.CurrentCulture);
var max = Convert.ToInt32(intarray[], CultureInfo.CurrentCulture);
var maxthen = Expression.GreaterThan(memberExpression, Expression.Constant(min, type));
var minthen = Expression.LessThan(memberExpression, Expression.Constant(max, type));
return Expression.Lambda<Func<T, bool>>(maxthen, parameterExpression)
.And(Expression.Lambda<Func<T, bool>>(minthen, parameterExpression));
case "decimal":
var decarray = ( (string)fieldValue ).Split(new char[] { '-' }, StringSplitOptions.RemoveEmptyEntries);
var dmin = Convert.ToDecimal(decarray[], CultureInfo.CurrentCulture);
var dmax = Convert.ToDecimal(decarray[], CultureInfo.CurrentCulture);
var dmaxthen = Expression.GreaterThan(memberExpression, Expression.Constant(dmin, type));
var dminthen = Expression.LessThan(memberExpression, Expression.Constant(dmax, type));
return Expression.Lambda<Func<T, bool>>(dmaxthen, parameterExpression)
.And(Expression.Lambda<Func<T, bool>>(dminthen, parameterExpression));
case "float":
var farray = ((string)fieldValue).Split(new char[] { '-' }, StringSplitOptions.RemoveEmptyEntries);
var fmin = Convert.ToDecimal(farray[], CultureInfo.CurrentCulture);
var fmax = Convert.ToDecimal(farray[], CultureInfo.CurrentCulture);
var fmaxthen = Expression.GreaterThan(memberExpression, Expression.Constant(fmin, type));
var fminthen = Expression.LessThan(memberExpression, Expression.Constant(fmax, type));
return Expression.Lambda<Func<T, bool>>(fmaxthen, parameterExpression)
.And(Expression.Lambda<Func<T, bool>>(fminthen, parameterExpression));
case "string":
var strarray = ( (string)fieldValue ).Split(new char[] { '-' }, StringSplitOptions.RemoveEmptyEntries);
var smin = strarray[];
var smax = strarray[]; var strmethod = typeof(string).GetMethod("Contains");
var mm = Expression.Call(memberExpression, strmethod, Expression.Constant(smin, type));
var nn = Expression.Call(memberExpression, strmethod, Expression.Constant(smax, type)); return Expression.Lambda<Func<T, bool>>(mm, parameterExpression)
.Or(Expression.Lambda<Func<T, bool>>(nn, parameterExpression));
default:
return x => true;
} } private static Expression<Func<T, bool>> Any<T, T2>(object fieldValue, ParameterExpression parameterExpression, MemberExpression memberExpression)
{
var lambda = (Expression<Func<T2, bool>>)fieldValue;
var anyMethod = typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public)
.First(m => m.Name == "Any" && m.GetParameters().Count() == ).MakeGenericMethod(typeof(T2)); var body = Expression.Call(anyMethod, memberExpression, lambda); return Expression.Lambda<Func<T, bool>>(body, parameterExpression);
} private static PropertyDescriptor GetProperty(PropertyDescriptorCollection props, string fieldName, bool ignoreCase)
{
if (!fieldName.Contains('.'))
{
return props.Find(fieldName, ignoreCase);
} var fieldNameProperty = fieldName.Split('.');
return props.Find(fieldNameProperty[], ignoreCase).GetChildProperties().Find(fieldNameProperty[], ignoreCase); }
#endregion
} internal class SwapVisitor : ExpressionVisitor
{
private readonly Expression from, to;
public SwapVisitor(Expression from, Expression to)
{
this.from = from;
this.to = to;
}
public override Expression Visit(Expression node) => node == from ? to : base.Visit(node);
}
public enum OperationExpression
{
equal,
notequal,
less,
lessorequal,
greater,
greaterorequal,
contains,
beginwith,
endwith,
includes,
between,
any
}
}

 public async Task<JsonResult> GetData(int page = , int rows = , string sort = "Id", string order = "asc", string filterRules = "")
{
try
{
var filters = PredicateBuilder.FromFilter<Company>(filterRules);
var total = await this.companyService
.Query(filters)
.AsNoTracking()
.CountAsync()
;
var pagerows = (await this.companyService
.Query(filters)
.AsNoTracking()
.OrderBy(n => n.OrderBy(sort, order))
.Skip(page - ).Take(rows)
.SelectAsync())
.Select(n => new
{
Id = n.Id,
Name = n.Name,
Code = n.Code,
Address = n.Address,
Contect = n.Contect,
PhoneNumber = n.PhoneNumber,
RegisterDate = n.RegisterDate.ToString("yyyy-MM-dd HH:mm:ss")
}).ToList();
var pagelist = new { total = total, rows = pagerows };
return Json(pagelist);
}
catch(Exception e) {
throw e;
} }

配合使用的代码

  • 对于固定查询逻辑的封装和复用,当然除了复用还可以明显的提高代码的可读性.

public class OrderSalesQuery : QueryObject<Order>
{
public decimal Amount { get; set; }
public string Country { get; set; }
public DateTime FromDate { get; set; }
public DateTime ToDate { get; set; } public override Expression<Func<Order, bool>> Query()
{
return (x =>
x.OrderDetails.Sum(y => y.UnitPrice) > Amount &&
x.OrderDate >= FromDate &&
x.OrderDate <= ToDate &&
x.ShipCountry == Country);
}
}

查看订单的销售情况,条件 金额,国家,日期

var orderRepository = new Repository<Order>(this);

var orders = orderRepository
.Query(new OrderSalesQuery(){
Amount = ,
Country = "USA",
FromDate = DateTime.Parse("01/01/1996"),
ToDate = DateTime.Parse("12/31/1996" )
})
.Select();

调用查询方法

public class CustomerLogisticsQuery : QueryObject<Customer>
{
public CustomerLogisticsQuery FromCountry(string country)
{
Add(x => x.Country == country);
return this;
} public CustomerLogisticsQuery LivesInCity(string city)
{
Add(x => x.City == city);
return this;
}
}

客户查询 根据国家和城市查询

public class CustomerSalesQuery : QueryObject<Customer>
{
public CustomerSalesQuery WithPurchasesMoreThan(decimal amount)
{
Add(x => x.Orders
.SelectMany(y => y.OrderDetails)
.Sum(z => z.UnitPrice * z.Quantity) > amount); return this;
} public CustomerSalesQuery WithQuantitiesMoreThan(decimal quantity)
{
Add(x => x.Orders
.SelectMany(y => y.OrderDetails)
.Sum(z => z.Quantity) > quantity); return this;
}
}

客户的销售情况,金额和数量

var customerRepository = new Repository<Customer>(this);

var query1 = new CustomerLogisticsQuery()
.LivesInCity("London"); var query2 = new CustomerSalesQuery()
.WithPurchasesMoreThan()
.WithQuantitiesMoreThan(); customerRepository
.Query(query1.And(query2))
.Select()
.Dump();

复用上面的定义的查询方法

以上这些都是改项目提供的方法,非常的好用

基于领域驱动设计(DDD)超轻量级快速开发架构(二)动态linq查询的实现方式的更多相关文章

  1. 基于领域驱动设计(DDD)超轻量级快速开发架构

    smartadmin.core.urf 这个项目是基于asp.net core 3.1(最新)基础上参照领域驱动设计(DDD)的理念,并参考目前最为了流行的abp架构开发的一套轻量级的快速开发web ...

  2. 领域驱动设计(DDD)

    领域驱动设计(DDD)实现之路 2004年,当Eric Evans的那本<领域驱动设计——软件核心复杂性应对之道>(后文简称<领域驱动设计>)出版时,我还在念高中,接触到领域驱 ...

  3. 领域驱动设计(DDD:Domain-Driven Design)

    领域驱动设计(DDD:Domain-Driven Design) Eric Evans的"Domain-Driven Design领域驱动设计"简称DDD,Evans DDD是一套 ...

  4. python 全栈开发,Day116(可迭代对象,type创建动态类,偏函数,面向对象的封装,获取外键数据,组合搜索,领域驱动设计(DDD))

    昨日内容回顾 1. 三个类 ChangeList,封装列表页面需要的所有数据. StarkConfig,生成URL和视图对应关系 + 默认配置 AdminSite,用于保存 数据库类 和 处理该类的对 ...

  5. 关于领域驱动设计 DDD(Domain-Driven Design)

    以下旨在 理解DDD. 1.     什么是领域? 妈妈好是做母婴新零售的产品,应该属于电商平台,那么电商平台就是一个领域. 同一个领域的系统都有相同的核心业务. eg: 电商领域都有:商品浏览.购物 ...

  6. 分享我对领域驱动设计(DDD)的学习成果

    本文内容提要: 1. 领域驱动设计之领域模型 2. 为什么建立一个领域模型是重要的 3. 领域通用语言(Ubiquitous Language) 4.将领域模型转换为代码实现的最佳实践 5. 领域建模 ...

  7. 我对领域驱动设计(DDD)的学习成果

    领域驱动设计之领域模型 2004年Eric Evans发表Domain-Driven Design – Tackling Complexity in the Heart of Software (领域 ...

  8. 领域驱动设计(DDD)实践之路(一)

    本文首发于 vivo互联网技术 微信公众号 链接: https://mp.weixin.qq.com/s/gk-Hb84Dt7JqBRVkMqM7Eg  作者:张文博 领域驱动设计(Domain Dr ...

  9. 领域驱动设计(DDD)实现之路

    2004年,当Eric Evans的那本<领域驱动设计——软件核心复杂性应对之道>(后文简称<领域驱动设计>)出版时,我还在念高中,接触到领域驱动设计(DDD)已经是8年后的事 ...

随机推荐

  1. 12.Java连接Redis_Jedis_常用API

    上一篇总结我们使用我们本地的Eclipse中创建的jedis工程,链接到了我们处于VMware虚拟机上的Linux系统上的Redis服务,我们接下来讲一下jedis的一些常用的API. (1)jedi ...

  2. 01 . Tomcat简介及部署

    Tomcat简介 Tomcat背景 tomcat就是常用的的中间件之一,tomcat本身是一个容器,专门用来运行java程序,java语言开发的网页.jsp就应该运行于tomcat中.而tomcat本 ...

  3. 上位机C#通过OPCUA和西门子PLC通信

    写在前面: 很多人在学习OPCUA的时候,有个非常苦恼的问题,就是没有OPCUA服务器的环境,这时候,有些人可能会想到通过类似于KepServer这样的软件来实现.那么,有没有一种方式,实现快速搭建O ...

  4. LayUI laydate日期选择器自定义 快捷选中今天、昨天 、本周、本月等等

    1. 引入laydata插件 下载 https://blog-static.cnblogs.com/files/zhangning187/laydate.js laydate.js 替换laydate ...

  5. Bootstrap解决页面缩小变形的办法

    bootstrap布局是应用得很广泛的一种网页布局方法,例如:我们用一种中间内容很流行的布局分布:3-6-3式布局.代码如下 <style type="text/css"&g ...

  6. Java实现 LeetCode 833 字符串中的查找与替换(暴力模拟)

    833. 字符串中的查找与替换 对于某些字符串 S,我们将执行一些替换操作,用新的字母组替换原有的字母组(不一定大小相同). 每个替换操作具有 3 个参数:起始索引 i,源字 x 和目标字 y.规则是 ...

  7. Java实现 LeetCode 781 森林中的兔子(分析题)

    781. 森林中的兔子 森林中,每个兔子都有颜色.其中一些兔子(可能是全部)告诉你还有多少其他的兔子和自己有相同的颜色.我们将这些回答放在 answers 数组里. 返回森林中兔子的最少数量. 示例: ...

  8. Java实现 LeetCode 547 朋友圈(并查集?)

    547. 朋友圈 班上有 N 名学生.其中有些人是朋友,有些则不是.他们的友谊具有是传递性.如果已知 A 是 B 的朋友,B 是 C 的朋友,那么我们可以认为 A 也是 C 的朋友.所谓的朋友圈,是指 ...

  9. Java实现 洛谷 P1423 小玉在游泳

    import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner in = ...

  10. Java实现表达式计算求值

    问题描述 输入一个只包含加减乖除和括号的合法表达式,求表达式的值.其中除表示整除. 输入格式 输入一行,包含一个表达式. 输出格式 输出这个表达式的值. 样例输入 1-2+3*(4-5) 样例输出 - ...