JFinal使用技巧-MyJson简易JSON字符串解析工具类

开年以来项目上一直在忙。。。一直没分享啥有意思的东西,前端时间在社区看到关于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

划水篇~

评论区

JFinal

2025-06-15 16:22

实现非常简单,先收藏,后面有用

热门分享

扫码入社