开年以来项目上一直在忙。。。一直没分享啥有意思的东西,前端时间在社区看到关于json工具的讨论。我们也有相应的烦恼,以前非常喜欢使用FastJson,API使用简洁速度还快。但是出了几档子事儿之后,我们有Y企客户,扫描到该jar后,进行了相关处理。以及后面又使用了HuToolJson等工具。再后来新项目上干脆自己撸了一个json字符串解析工具,因为我们json字符串都比较小,就是表单对象或者是有数组对象的表单对象业务,非常简单,不需要使用什么反射之类的业务。
算了废话不多说了,上马吧:
创建一个 MyJson,因为JsonKit 是JF内置的工具类,所以起个MyJson名。
该工具没有实现JF内置的Json接口,因为toJson方法JF的JFinalJson已经非常OK,只是parse未实现。但是parse方法参数是parse(String jsonString, Class<T> type) Class并不是我们想要的,我们常见就 KV对象,或者 Record 对象,list对象即可了。
反射Class实现起来也麻烦,最主要的是目前用不上。 所以干脆写个独立的工具类即可了。
import com.jfinal.kit.Kv; import com.jfinal.plugin.activerecord.Record; import java.util.ArrayList; /** * 简易JSON字符串解析工具类 * @author 杜福忠 */ @SuppressWarnings("unused") public class MyJson { private String jsonStr; private int index; private boolean kvToRecord = false; public static MyJson getJson() { return new MyJson(); } public Object parse(String jsonString) { this.jsonStr = jsonString.trim(); this.index = 0; return parseValue(); } public static Kv parseKv(String jsonString) { return (Kv) getJson().parse(jsonString); } @SuppressWarnings("unchecked") public static ArrayList<Object> parseList(String jsonString) { return (ArrayList<Object>) getJson().parse(jsonString); } public static Record parseRecord(String jsonString) { return (Record) getJson().setKvToRecord(true).parse(jsonString); } @SuppressWarnings("unchecked") public static ArrayList<Record> parseRecordList(String jsonString) { return (ArrayList<Record>) getJson().setKvToRecord(true).parse(jsonString); } public MyJson setKvToRecord(boolean kvToRecord) { this.kvToRecord = kvToRecord; return this; } private Object parseValue() { skipWhitespace(); char current = jsonStr.charAt(index); if (current == '{') return parseKv(); else if (current == '[') return parseList(); else if (current == '"') return parseString(); else if (current == '-' || Character.isDigit(current)) return parseNumber(); else if (current == 't' || current == 'f' || current == 'T' || current == 'F') return parseBoolean(); else if (current == 'n' || current == 'N') return parseNull(); else throw new RuntimeException("JSON字符串解析错误:(" + index + ")>" + current); } private void skipWhitespace() { while (index < jsonStr.length() && Character.isWhitespace(jsonStr.charAt(index))){ index++; } } private StringBuilder parseString_sb; private String parseString() { if (parseString_sb == null){ parseString_sb = new StringBuilder(); } index++; // 跳过开头引号 while (index < jsonStr.length()) { char c = jsonStr.charAt(index++); if (c == '"') break; else if (c == '\\') { c = jsonStr.charAt(index++); parseString_sb.append(c); // 简化处理转义符(如 \" → ") } else parseString_sb.append(c); } String ret = parseString_sb.toString(); parseString_sb.setLength(0); return ret; } private Object parseKv() { Object kv = kvToRecord ? new Record() : new Kv(); index++; // 跳过 '{' while (true) { skipWhitespace(); if (jsonStr.charAt(index) == '}') { index++; return kv; } String key = parseString(); skipWhitespace(); if (jsonStr.charAt(index++) != ':') { throw new RuntimeException("JSON字符串解析错误:(" + index + ")>" + key + "对象无':'符号"); } Object value = parseValue(); if (kv instanceof Kv) { ((Kv)kv).set(key, value); }else{ ((Record)kv).set(key, value); } skipWhitespace(); if (jsonStr.charAt(index) == ',') { index++; }else if (jsonStr.charAt(index) != '}') { throw new RuntimeException("JSON字符串解析错误:(" + index + ")>" + key + "对象的后面应该是','或者'}'"); } } } private ArrayList<Object> parseList() { ArrayList<Object> list = new ArrayList<>(); index++; // 跳过 '[' while (true) { skipWhitespace(); if (jsonStr.charAt(index) == ']') { index++; return list; } Object value = parseValue(); list.add(value); skipWhitespace(); if (jsonStr.charAt(index) == ','){ index++; }else if (jsonStr.charAt(index) != ']'){ throw new RuntimeException("JSON字符串解析错误:(" + index + ")>应该是','或者']'符号"); } } } private Object parseNull() { if (jsonStr.startsWith("null", index) || jsonStr.startsWith("NULL", index)) { index += 4; return null; } throw new RuntimeException("JSON字符串解析错误:(" + index + ")>不是 null 符号"); } private Boolean parseBoolean() { if (jsonStr.startsWith("true", index) || jsonStr.startsWith("TRUE", index)) { index += 4; return Boolean.TRUE; } else if (jsonStr.startsWith("false", index) || jsonStr.startsWith("FALSE", index)) { index += 5; return Boolean.FALSE; } throw new RuntimeException("JSON字符串解析错误:(" + index + ")>不是 boolean 符号"); } private Number parseNumber() { int start = index; while (index < jsonStr.length() && (Character.isDigit(jsonStr.charAt(index)) || jsonStr.charAt(index) == '-' || jsonStr.charAt(index) == '.')) { index++; } String numStr = jsonStr.substring(start, index); if (numStr.contains(".")) return Double.parseDouble(numStr); else return Long.parseLong(numStr); } }
可以看到有几个静态方法:
public static Kv parseKv(String jsonString) public static ArrayList<Object> parseList(String jsonString) public static Record parseRecord(String jsonString) public static ArrayList<Record> parseRecordList(String jsonString)
键值对象使用Kv对象是非常的棒,Kv对象自带数据类型的转换,kv.getInt > getStr >getDate 等等方法,Record也是一样自带数据类型转换。所以可以使得json解析方法非常简单,不用关注太多类型转换问题。
下面展示一个Kv用法例子:
public static void main(String[] args) { String jsonStr = "{ \"name\": \"John\", \"age\": 30, \"list\": [90, 85, 71], \"obj\": { \"name\": \"John\", \"age\": 30}}"; Kv kv = MyJson.parseKv(jsonStr); Integer age = kv.getInt("age"); System.out.println(age); List<Long> list = kv.getAs("list"); for (Long x : list) { System.out.println(x); } Kv obj = kv.getAs("obj"); System.out.println(obj.getStr("name")); }
可以看到 kv.getAs 获取对象或者集合都非常方便。
特别是泛型上面的处理使用比FastJson要方便很多。在普通json字符串对象的解析上性能也是嗷嗷领先,毕竟代码少功能还简单,执行自然快。。。
Record 也是一样:
public static void main(String[] args) { String jsonStr = "{ \"name\": \"John\", \"age\": 30, \"list\": [90, 85, 71], \"obj\": { \"name\": \"John\", \"age\": 30}}"; Record r = MyJson.parseRecord(jsonStr); Integer age = r.getInt("age"); System.out.println(age); List<Long> list = r.get("list"); for (Long x : list) { System.out.println(x); } Record obj = r.get("obj"); System.out.println(obj.getStr("name")); }
入数据库的业务,都不用map转换对象了,直接用,非常方便。
好了,分享到此结束!只适合部分业务场景。
如果需要反射类的业务处理,也可以自行改造一下支持。可参考我之前分享的一个例子:
Record转JavaBean以及List转JavaBea
划水篇~