java json u0026_简易的Json转换的实现

环境

数据库字段中保存着Json数据,用于保存用户的权限,这些Json数据,不需要数据库去处理。 这似乎是一个生命中常见的命题,本来不可能,却非有人要打破它。

菜单表是自增ID

权限字如下,表示角色拥有的页面权限,按钮权限,行集权限,行集权限包括 查看权限,修改权限,删除权限。 查看权限描述了可以查看 哪些表的 哪些行。 其中 表的哪些行是用一个大数字来保存的。

{Action:"0",Button:"0",Row:{View:{Menu:"F,FFC00000,0,0,3E0004"},Edit:{},Delete:{},IsMax:false},IsMax:false}

其中Menu后面的一大串是大数字。逗号分隔的每个部分是一个uint , 表示在该2进制位上是否拥有该菜单 。 如  5 表示角色拥有 第1行 和第3 行菜单 。 5 的二进制编码是  101  = 1 * 2^2 + 0 * 2^1 + 1 * 2^0 , 即: 第一行和第三行。

为了描述简单,把从权限字中计算得到的菜单表的行集称为 权限行集,

遇到的问题

设计人员提出:用脚本设置角色的权限。如,给所有角色添加一个菜单权限。

该功能在程序端的实现方式是,对权限字反序列化到对象上,把大数字取出,进行位运算,取出权限行集,与设置菜单ID 进行合并(增加一行或删除一行)。

如果在数据库上实现该功能,最好还是用.Net 来完成。

在数据库端的实现

在Sqlserver 2008 + 上,可以编写.net 程序集对sqlserver扩展, 好像java也可以对oracle 进行扩展。

最初的想法是 在数据库上引用 Json.Net ,再创建一个自定义程序集,自定义程序集引用数据库的Json.Net 。 但数据库上的程序集有诸多条件: http://msdn.microsoft.com/en-us/library/ms189524.aspx , 最典型的是 static 必须是 readonly 的。我把Json.Net 2.0 的程序集按要求改了之后,注入还是出错: 收集元数据时出错 。所以只能再找办法。

由于Json是比较简单的形式,所以决定自己写一个 Json 的反序列化。

过程比较简单: 建一个 C# CLR 数据库项目。

确定以下规则:

1. 反斜线是转义,反斜线后面的字符可忽略规则。

2. 引号是整体

3. 冒号分词

4. { } , [] 算是一个整体 可以无限级。

编写的方式要简单,原始。输入参数:JSON,KEY , 返回 KEY 后表示的Value 字符串。

代码如下:

[SqlFunction]public static SqlString GetJsonValue(string Value, stringKey)

{//返回一个string 数组,这个数组符合IEnumerable接口,当然你也可以返回hashtable等类型。

Value =Value.Trim();if (!Value.StartsWith("{") || !Value.EndsWith("}")) throw new Exception("非法Json");/** 规则:

* 1. 反斜线是转义,反斜线后面的字符可忽略规则。

* 2. 引号是整体

* 3. 冒号分词

* 4. { } 算是一个整体 可以无限级。*/Value= Value.Substring(1, Value.Length - 2);for (var i = 0; i < Value.Length; i++)

{int keyEndIndex = PowerJson.FindNext(Value, i, ':');var key = Value.Substring(i, keyEndIndex -i).Trim();var valueEndIndex = PowerJson.FindNext(Value, keyEndIndex + 1, ',');

i=valueEndIndex;var val = Value.Substring(keyEndIndex + 1, valueEndIndex - keyEndIndex - 1).Trim();if (key.StartsWith(@"""") && key.EndsWith(@"""")) key = key.Substring(1, key.Length - 2);if (val.StartsWith(@"""") && val.EndsWith(@"""")) val = val.Substring(1, val.Length - 2);if (string.Equals(key, Key, StringComparison.CurrentCultureIgnoreCase)) returnval;

}return string.Empty;

}

PowerJson 的分词函数:

public static int FindNext(string Value, int pos, charfindChar)

{/** 规则:

* 1. 反斜线是转义,反斜线后面的字符可忽略规则。

* 2. 双引号是整体,单引号是整体

* 3. {} 是整体,[] 是整体。

* 4. 冒号分词*/

//结束

if (pos == Value.Length) returnValue.Length;int ClsLevel = 0;int AryLevel = 0;bool inQuote1 = false;bool inQuote2 = false;for (int i = pos; i < Value.Length; i++)

{var item =Value[i];if (item == '\\')

{

i++;continue;

}if (ClsLevel == 0 && AryLevel == 0 && inQuote1 == false && inQuote2 == false && findChar == item) returni;if(inQuote1)

{if (item == '\'')

{

inQuote1= !inQuote1;

}continue;

}if(inQuote2)

{if (item == '"')

{

inQuote2= !inQuote2;

}continue;

}if (inQuote1 == false && inQuote2 == false)

{if (item == '\'')

{

inQuote1= true;continue;

}if (item == '"')

{

inQuote2= true;continue;

}

}if (item == '{')

{

ClsLevel++;continue;

}if (item == '}')

{

ClsLevel--;continue;

}if (item == '[')

{

AryLevel++;continue;

}if (item == ']')

{

AryLevel--;continue;

}

}returnValue.Length;

}

使用SQL把程序集注入:

---

exec sp_configure 'show advanced options', '1';go

reconfigure;go

exec sp_configure 'clr enabled', '1'

go

reconfigure;exec sp_configure 'show advanced options', '1';go

CREATEASSEMBLY MyCLrFROM 'G:\共享\个人共享\Udi\MyClr\MyClr.dll'

WITH permission_set =Safe;GO

CREATE FUNCTION [dbo].[GetJsonValue](@val [nvarchar](4000), @key nvarchar(200))RETURNS [nvarchar](4000) WITH EXECUTE ASCALLERASEXTERNAL NAME[MyClr].[MyClr].[GetJsonValue]

go

在数据库端进行测试,取出Row.View.Menu的值:

select dbo.GetJsonValue( dbo.GetJsonValue( dbo.GetJsonValue( [Power],'Row'),'View'),'Menu') from [Role]

得到的是大数字。

后续的大数字计算,由于SQL server 程序集只能使用 .net 3.5 ,所以 .Net 4.0 的大数字System.Numerics.BigInteger 就不能使用了,可以参考开源的,如下:

我在BigInt 的基础上稍做修改,主要是格式化输出,和对格式化输出进行解析。 有了开源的实现,这就容易多了。

实现之后感觉反序列Json还是非常简单的。在轻量级应用上,非常方便。

经测试,性能还不错。

JOSN转义问题

对象 =》 JSON 字符串 ,需要把 真回车"\n" 转换为 字符串 "\\n"

反之

Json字符串 =》 对象,需要把字符串中的回车 "\\n" 转换为 "\n"

要处理的字符包括:

\\r  => \r

\\n  => \n

\\t  => \t

\\"  => \"

\\'  => \'

最后处理

\\\\ => \\

\\u0026 => &  等特殊字符。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值