From 7b3d2f460d8d886fd500efe2dbdefbed18dd89c8 Mon Sep 17 00:00:00 2001 From: utilcore <8907060@qq.com> Date: Mon, 30 Oct 2017 08:47:14 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=8F=82=E6=95=B0=E7=94=9F?= =?UTF-8?q?=E6=88=90=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- readme.md | 2 + src/Util/01-Util.csproj | 4 + .../Parameters/Formats/IParameterFormat.cs | 19 ++ .../Parameters/Formats/ParameterFormatBase.cs | 38 ++++ .../Parameters/Formats/UrlParameterFormat.cs | 21 +++ src/Util/Parameters/ParameterBuilder.cs | 106 +++++++++++ src/Util/Parameters/UrlParameterBuilder.cs | 89 ++++++++++ src/Util/Webs/Clients/IHttpRequest.cs | 84 --------- src/Util/Webs/Clients/IRequest.cs | 89 ++++++++++ .../Parameters/ParameterBuilderTest.cs | 166 ++++++++++++++++++ .../Parameters/UrlParameterBuilderTest.cs | 66 +++++++ .../Samples/ParameterFormatterSample.cs | 18 ++ 12 files changed, 618 insertions(+), 84 deletions(-) create mode 100644 src/Util/Parameters/Formats/IParameterFormat.cs create mode 100644 src/Util/Parameters/Formats/ParameterFormatBase.cs create mode 100644 src/Util/Parameters/Formats/UrlParameterFormat.cs create mode 100644 src/Util/Parameters/ParameterBuilder.cs create mode 100644 src/Util/Parameters/UrlParameterBuilder.cs create mode 100644 src/Util/Webs/Clients/IRequest.cs create mode 100644 test/Util.Tests/Parameters/ParameterBuilderTest.cs create mode 100644 test/Util.Tests/Parameters/UrlParameterBuilderTest.cs create mode 100644 test/Util.Tests/Samples/ParameterFormatterSample.cs diff --git a/readme.md b/readme.md index 4021ffc4..af096d56 100644 --- a/readme.md +++ b/readme.md @@ -362,6 +362,7 @@ https://github.com/dotnetcore/util/ - 二维码操作 - 基于QRCoder [已发布] - 短信操作 -基于LuoSiMao [已发布] - 加密操作 [已发布] + - Url参数生成器 [已发布] - 分层架构基类及组件 - 实体基类 [已发布] - 聚合根基类 [已发布] @@ -426,3 +427,4 @@ https://github.com/dotnetcore/util/ - 2017年10月21日,更新了Ui组件基类及TagHelper基类,图标组件(Util.Ui.Angular/Material/Icons)及单元测试。 - 2017年10月25日,更新了二维码操作(Util.Tools.QrCode,基于QRCoder)和短信操作(Util.Tools.Sms,封装了LuoSiMao接口)。 - 2017年10月29日,更新了加密操作(Util.Helpers.Encrypt,集成了MD5,DES,AES,RSA加密操作)及单元测试。 +- 2017年10月30日,更新了Url参数生成器(Util.Parameters)及单元测试。 diff --git a/src/Util/01-Util.csproj b/src/Util/01-Util.csproj index 2aef6820..6d5c35c3 100644 --- a/src/Util/01-Util.csproj +++ b/src/Util/01-Util.csproj @@ -74,4 +74,8 @@ Util是一个.net core平台下的应用框架,旨在提升小型团队的开 + + + + \ No newline at end of file diff --git a/src/Util/Parameters/Formats/IParameterFormat.cs b/src/Util/Parameters/Formats/IParameterFormat.cs new file mode 100644 index 00000000..30b207c4 --- /dev/null +++ b/src/Util/Parameters/Formats/IParameterFormat.cs @@ -0,0 +1,19 @@ +namespace Util.Parameters.Formats { + /// + /// 参数格式化器 + /// + public interface IParameterFormat { + /// + /// 格式化 + /// + /// 键 + /// 值 + string Format( string key, string value ); + /// + /// 连接参数 + /// + /// 左操作数 + /// 右操作数 + string Join( string left, string right ); + } +} diff --git a/src/Util/Parameters/Formats/ParameterFormatBase.cs b/src/Util/Parameters/Formats/ParameterFormatBase.cs new file mode 100644 index 00000000..5c279195 --- /dev/null +++ b/src/Util/Parameters/Formats/ParameterFormatBase.cs @@ -0,0 +1,38 @@ +namespace Util.Parameters.Formats { + /// + /// 参数格式化器 + /// + public abstract class ParameterFormatBase : IParameterFormat { + /// + /// 格式化 + /// + /// 键 + /// 值 + public string Format( string key, string value ) { + return $"{key}{FormatSeparator}{value}"; + } + + /// + /// 格式化分割符 + /// + protected abstract string FormatSeparator { get; } + + /// + /// 连接参数 + /// + /// 左操作数 + /// 右操作数 + public string Join( string left, string right ) { + if ( string.IsNullOrWhiteSpace( left ) ) + return right; + if ( string.IsNullOrWhiteSpace( right ) ) + return left; + return $"{left}{JoinSeparator}{right}"; + } + + /// + /// 连接符 + /// + protected abstract string JoinSeparator { get; } + } +} diff --git a/src/Util/Parameters/Formats/UrlParameterFormat.cs b/src/Util/Parameters/Formats/UrlParameterFormat.cs new file mode 100644 index 00000000..2d876034 --- /dev/null +++ b/src/Util/Parameters/Formats/UrlParameterFormat.cs @@ -0,0 +1,21 @@ +namespace Util.Parameters.Formats { + /// + /// Url参数格式化器 + /// + internal class UrlParameterFormat : ParameterFormatBase { + /// + /// Url参数格式化器实例 + /// + public static readonly IParameterFormat Instance = new UrlParameterFormat(); + + /// + /// 格式化分割符 + /// + protected override string FormatSeparator => "="; + + /// + /// 连接符 + /// + protected override string JoinSeparator => "&"; + } +} diff --git a/src/Util/Parameters/ParameterBuilder.cs b/src/Util/Parameters/ParameterBuilder.cs new file mode 100644 index 00000000..f9a336a8 --- /dev/null +++ b/src/Util/Parameters/ParameterBuilder.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using Util.Parameters.Formats; + +namespace Util.Parameters { + /// + /// 参数生成器 + /// + public class ParameterBuilder { + /// + /// 参数集合 + /// + private readonly Dictionary _params; + + /// + /// 初始化参数生成器 + /// + public ParameterBuilder() { + _params = new Dictionary(); + } + + /// + /// 添加参数,如果参数已存在则替换 + /// + /// 键 + /// 值 + public ParameterBuilder Add( string key, object value ) { + if( string.IsNullOrWhiteSpace( key ) ) + return this; + string strValue = GetValue( value ).Trim(); + if( string.IsNullOrWhiteSpace( strValue ) ) + return this; + key = key.Trim(); + if( _params.ContainsKey( key ) ) + _params[key] = strValue; + else + _params.Add( key, strValue ); + return this; + } + + /// + /// 获取值 + /// + private string GetValue( object value ) { + if( value is string ) + return value.ToString(); + if( value is DateTime dateTime ) + return dateTime.ToString( "yyyy-MM-dd HH:mm:ss" ); + if( value is bool boolValue ) + return boolValue.ToString().ToLower(); + return value.SafeString(); + } + + /// + /// 获取字典 + /// + public IDictionary GetDictionary() { + return _params; + } + + /// + /// 获取键值对集合 + /// + public IEnumerable> GetKeyValuePairs() { + return _params; + } + + /// + /// 清空 + /// + public void Clear() { + _params.Clear(); + } + + /// + /// 移除参数 + /// + /// 键 + public bool Remove( string key ) { + return _params.Remove( key ); + } + + /// + /// 获取结果 + /// + /// 参数格式化器 + /// 是否按参数名排序 + public string Result( IParameterFormat format, bool isSort = false ) { + if( format == null ) + throw new ArgumentNullException( nameof( format ) ); + var result = string.Empty; + foreach( var param in GetDictionary( isSort ) ) + result = format.Join( result, format.Format( param.Key, param.Value ) ); + return result; + } + + /// + /// 获取字典 + /// + private IDictionary GetDictionary( bool isSort ) { + if( isSort == false ) + return _params; + return new SortedDictionary( _params ); + } + } +} \ No newline at end of file diff --git a/src/Util/Parameters/UrlParameterBuilder.cs b/src/Util/Parameters/UrlParameterBuilder.cs new file mode 100644 index 00000000..f082e0b4 --- /dev/null +++ b/src/Util/Parameters/UrlParameterBuilder.cs @@ -0,0 +1,89 @@ +using System.Collections.Generic; +using Util.Parameters.Formats; + +namespace Util.Parameters { + /// + /// Url参数生成器 + /// + public class UrlParameterBuilder { + /// + /// 参数生成器 + /// + private readonly ParameterBuilder _builder; + + /// + /// 初始化Url参数生成器 + /// + public UrlParameterBuilder() { + _builder = new ParameterBuilder(); + } + + /// + /// 添加参数 + /// + /// 键 + /// 值 + public UrlParameterBuilder Add( string key, object value ) { + _builder.Add( key, value ); + return this; + } + + /// + /// 获取字典 + /// + public IDictionary GetDictionary() { + return _builder.GetDictionary(); + } + + /// + /// 获取键值对集合 + /// + public IEnumerable> GetKeyValuePairs() { + return _builder.GetKeyValuePairs(); + } + + /// + /// 获取结果,格式:参数名=参数值&参数名=参数值 + /// + /// 是否按参数名排序 + public string Result( bool isSort = false ) { + return _builder.Result( UrlParameterFormat.Instance, isSort ); + } + + /// + /// 连接Url + /// + /// 地址 + public string JoinUrl( string url ) { + return $"{GetUrl( url )}{Result()}"; + } + + /// + /// 获取Url + /// + private string GetUrl( string url ) { + if( !url.Contains( "?" ) ) + return $"{url}?"; + if( url.EndsWith( "?" ) ) + return url; + if( url.EndsWith( "&" ) ) + return url; + return $"{url}&"; + } + + /// + /// 清空 + /// + public void Clear() { + _builder.Clear(); + } + + /// + /// 移除参数 + /// + /// 键 + public bool Remove( string key ) { + return _builder.Remove( key ); + } + } +} diff --git a/src/Util/Webs/Clients/IHttpRequest.cs b/src/Util/Webs/Clients/IHttpRequest.cs index c88c8fed..134caff2 100644 --- a/src/Util/Webs/Clients/IHttpRequest.cs +++ b/src/Util/Webs/Clients/IHttpRequest.cs @@ -3,90 +3,6 @@ using System.Net; using System.Threading.Tasks; namespace Util.Webs.Clients { - /// - /// Http请求 - /// - public interface IRequest where TRequest : IRequest { - /// - /// 设置内容类型 - /// - /// 内容类型 - TRequest ContentType( HttpContentType contentType ); - /// - /// 设置内容类型 - /// - /// 内容类型 - TRequest ContentType( string contentType ); - /// - /// 设置Cookie - /// - /// 名称 - /// 值 - /// 有效时间,单位:天 - TRequest Cookie( string name, string value, double expiresDate ); - /// - /// 设置Cookie - /// - /// 名称 - /// 值 - /// 到期时间 - TRequest Cookie( string name, string value, DateTime expiresDate ); - /// - /// 设置Cookie - /// - /// 名称 - /// 值 - /// 源服务器URL子集 - /// 所属域 - /// 到期时间 - TRequest Cookie( string name, string value, string path = "/", string domain = null, DateTime? expiresDate = null ); - /// - /// 设置Cookie - /// - /// cookie - TRequest Cookie( Cookie cookie ); - /// - /// 超时时间 - /// - /// 超时时间,单位:秒 - TRequest Timeout( int timeout ); - /// - /// 请求头 - /// - /// 键 - /// 值 - TRequest Header( string key, T value ); - /// - /// 添加参数 - /// - /// 键 - /// 值 - TRequest Data( string key, T value ); - /// - /// 添加Json参数 - /// - /// 值 - TRequest JsonData( T value ); - /// - /// 请求失败回调函数 - /// - /// 执行失败的回调函数,参数为响应结果 - TRequest OnFail( Action action ); - /// - /// 请求失败回调函数 - /// - /// 执行失败的回调函数,第一个参数为响应结果,第二个参数为状态码 - TRequest OnFail( Action action ); - /// - /// 获取结果 - /// - string Result(); - /// - /// 获取结果 - /// - Task ResultAsync(); - } - /// /// Http请求 /// diff --git a/src/Util/Webs/Clients/IRequest.cs b/src/Util/Webs/Clients/IRequest.cs new file mode 100644 index 00000000..e8860b1f --- /dev/null +++ b/src/Util/Webs/Clients/IRequest.cs @@ -0,0 +1,89 @@ +using System; +using System.Net; +using System.Threading.Tasks; + +namespace Util.Webs.Clients { + /// + /// Http请求 + /// + public interface IRequest where TRequest : IRequest { + /// + /// 设置内容类型 + /// + /// 内容类型 + TRequest ContentType( HttpContentType contentType ); + /// + /// 设置内容类型 + /// + /// 内容类型 + TRequest ContentType( string contentType ); + /// + /// 设置Cookie + /// + /// 名称 + /// 值 + /// 有效时间,单位:天 + TRequest Cookie( string name, string value, double expiresDate ); + /// + /// 设置Cookie + /// + /// 名称 + /// 值 + /// 到期时间 + TRequest Cookie( string name, string value, DateTime expiresDate ); + /// + /// 设置Cookie + /// + /// 名称 + /// 值 + /// 源服务器URL子集 + /// 所属域 + /// 到期时间 + TRequest Cookie( string name, string value, string path = "/", string domain = null, DateTime? expiresDate = null ); + /// + /// 设置Cookie + /// + /// cookie + TRequest Cookie( Cookie cookie ); + /// + /// 超时时间 + /// + /// 超时时间,单位:秒 + TRequest Timeout( int timeout ); + /// + /// 请求头 + /// + /// 键 + /// 值 + TRequest Header( string key, T value ); + /// + /// 添加参数 + /// + /// 键 + /// 值 + TRequest Data( string key, T value ); + /// + /// 添加Json参数 + /// + /// 值 + TRequest JsonData( T value ); + /// + /// 请求失败回调函数 + /// + /// 执行失败的回调函数,参数为响应结果 + TRequest OnFail( Action action ); + /// + /// 请求失败回调函数 + /// + /// 执行失败的回调函数,第一个参数为响应结果,第二个参数为状态码 + TRequest OnFail( Action action ); + /// + /// 获取结果 + /// + string Result(); + /// + /// 获取结果 + /// + Task ResultAsync(); + } +} diff --git a/test/Util.Tests/Parameters/ParameterBuilderTest.cs b/test/Util.Tests/Parameters/ParameterBuilderTest.cs new file mode 100644 index 00000000..7f478690 --- /dev/null +++ b/test/Util.Tests/Parameters/ParameterBuilderTest.cs @@ -0,0 +1,166 @@ +using System; +using Util.Parameters; +using Util.Tests.Samples; +using Xunit; + +namespace Util.Tests.Parameters { + /// + /// 参数生成器测试 + /// + public class ParameterBuilderTest { + /// + /// 参数生成器 + /// + private readonly ParameterBuilder _dictionary; + + /// + /// 测试初始化 + /// + public ParameterBuilderTest() { + _dictionary = new ParameterBuilder(); + } + + /// + /// 验证key为空 + /// + [Theory] + [InlineData( null )] + [InlineData( "" )] + [InlineData( " " )] + public void TestAdd_KeyIsEmpty( string key ) { + Assert.Empty( _dictionary.Add( key, "b" ).Result( new ParameterFormatterSample() ) ); + } + + /// + /// 验证value为空 + /// + [Theory] + [InlineData( null )] + [InlineData( "" )] + [InlineData( " " )] + public void TestAdd_ValueIsEmpty( string value ) { + Assert.Empty( _dictionary.Add( "a", value ).Result( new ParameterFormatterSample() ) ); + } + + /// + /// 去除键两端空格 + /// + [Fact] + public void TestAdd_TrimKey() { + Assert.Equal( "a:1", _dictionary.Add( " a ", "1" ).Result( new ParameterFormatterSample() ) ); + } + + /// + /// 去除值两端空格 + /// + [Fact] + public void TestAdd_TrimValue() { + Assert.Equal( "a:1", _dictionary.Add( "a", " 1 " ).Result( new ParameterFormatterSample() ) ); + } + + /// + /// 添加字符串参数 + /// + [Fact] + public void TestAdd_String() { + Assert.Equal( "a:1", _dictionary.Add( "a", "1" ).Result( new ParameterFormatterSample() ) ); + } + + /// + /// 添加2个字符串参数 + /// + [Fact] + public void TestAdd_String_2() { + Assert.Equal( "a:1|b:2", _dictionary.Add( "a", " 1" ).Add( "b ", "2 " ).Result( new ParameterFormatterSample() ) ); + } + + /// + /// 添加日期参数 + /// + [Fact] + public void TestAdd_DateTime() { + DateTime value = new DateTime( 2000, 10, 10, 10, 10, 10 ); + Assert.Equal( "a:2000-10-10 10:10:10", _dictionary.Add( "a", value ).Result( new ParameterFormatterSample() ) ); + } + + /// + /// 添加日期参数 - 可空 + /// + [Fact] + public void TestAdd_DateTime_Nullable() { + DateTime? value = new DateTime( 2000, 10, 10, 10, 10, 10 ); + Assert.Equal( "a:2000-10-10 10:10:10", _dictionary.Add( "a", value ).Result( new ParameterFormatterSample() ) ); + } + + /// + /// 添加日期参数 - 可空 - 传入null + /// + [Fact] + public void TestAdd_DateTime_Nullable_Null() { + DateTime? value = null; + Assert.Empty( _dictionary.Add( "a", value ).Result( new ParameterFormatterSample() ) ); + } + + /// + /// 添加整型参数 + /// + [Fact] + public void TestAdd_Int() { + int value = 1; + Assert.Equal( "a:1", _dictionary.Add( "a", value ).Result( new ParameterFormatterSample() ) ); + } + + /// + /// 添加整型参数 - 可空 + /// + [Fact] + public void TestAdd_Int_Nullable() { + int? value = 1; + Assert.Equal( "a:1", _dictionary.Add( "a", value ).Result( new ParameterFormatterSample() ) ); + } + + /// + /// 添加整型参数 - 可空 - 传入null + /// + [Fact] + public void TestAdd_Int_Nullable_Null() { + int? value = null; + Assert.Empty( _dictionary.Add( "a", value ).Result( new ParameterFormatterSample() ) ); + } + + /// + /// 添加布尔参数 + /// + [Fact] + public void TestAdd_Bool() { + bool value = true; + Assert.Equal( "a:true", _dictionary.Add( "a", value ).Result( new ParameterFormatterSample() ) ); + } + + /// + /// 添加布尔参数 - 可空 + /// + [Fact] + public void TestAdd_Bool_Nullable() { + bool? value = false; + Assert.Equal( "a:false", _dictionary.Add( "a", value ).Result( new ParameterFormatterSample() ) ); + } + + /// + /// 添加布尔参数 - 可空 - 传入null + /// + [Fact] + public void TestAdd_Bool_Nullable_Null() { + bool? value = null; + Assert.Empty( _dictionary.Add( "a", value ).Result( new ParameterFormatterSample() ) ); + } + + /// + /// 已添加参数则覆盖 + /// + [Fact] + public void TestAdd_Exist() { + Assert.Equal( "a:2", _dictionary.Add( "a", "1" ).Add( "a", "2" ).Result( new ParameterFormatterSample() ) ); + } + } +} diff --git a/test/Util.Tests/Parameters/UrlParameterBuilderTest.cs b/test/Util.Tests/Parameters/UrlParameterBuilderTest.cs new file mode 100644 index 00000000..6547d603 --- /dev/null +++ b/test/Util.Tests/Parameters/UrlParameterBuilderTest.cs @@ -0,0 +1,66 @@ +using Util.Parameters; +using Xunit; + +namespace Util.Tests.Parameters { + /// + /// Url参数生成器测试 + /// + public class UrlParameterBuilderTest { + /// + /// Url参数生成器 + /// + private readonly UrlParameterBuilder _builder; + + /// + /// 测试初始化 + /// + public UrlParameterBuilderTest() { + _builder = new UrlParameterBuilder(); + } + + /// + /// 测试默认值 + /// + [Fact] + public void TestDefault() { + Assert.Empty( _builder.Result() ); + } + + /// + /// 添加参数 + /// + [Fact] + public void TestAdd_1() { + Assert.Equal( "a=b", _builder.Add( "a", "b" ).Result() ); + Assert.Equal( "a=b&c=d", _builder.Add( "c", "d" ).Result() ); + } + + /// + /// 添加参数 - 测试空格 + /// + [Fact] + public void TestAdd_2() { + Assert.Equal( "b=2&a=1", _builder.Add( " b ", " 2 " ).Add( " a ", " 1 " ).Result() ); + } + + /// + /// 添加参数 - 测试排序 + /// + [Fact] + public void TestResult_Sort() { + Assert.Equal( "a=1&b=2", _builder.Add( "b", "2" ).Add( "a", "1" ).Result( true ) ); + } + + /// + /// 连接URL + /// + [Theory] + [InlineData( "http://test.com", "http://test.com?a=1&b=2" )] + [InlineData( "http://test.com?", "http://test.com?a=1&b=2" )] + [InlineData( "http://test.com?c=3", "http://test.com?c=3&a=1&b=2" )] + [InlineData( "http://test.com?c=3&", "http://test.com?c=3&a=1&b=2" )] + public void TestJoinUrl( string url, string result ) { + Assert.Equal( result, _builder.Add( "a", "1" ).Add( "b", "2" ).JoinUrl( url ) ); + } + } +} diff --git a/test/Util.Tests/Samples/ParameterFormatterSample.cs b/test/Util.Tests/Samples/ParameterFormatterSample.cs new file mode 100644 index 00000000..fb32a6ac --- /dev/null +++ b/test/Util.Tests/Samples/ParameterFormatterSample.cs @@ -0,0 +1,18 @@ +using Util.Parameters.Formats; + +namespace Util.Tests.Samples { + /// + /// 参数格式化器样例 + /// + public class ParameterFormatterSample : ParameterFormatBase { + /// + /// 格式化分割符 + /// + protected override string FormatSeparator => ":"; + + /// + /// 连接符 + /// + protected override string JoinSeparator => "|"; + } +}