乐趣区

JSON工具类的构建后端版本

前言

在前后端交互的选择上,之前一直采用的是模板引擎 (因为我只负责后端)。
而这次的一个算是作业吧,前后端都是我,所以就研究了一下 JSON 交互在 java web 的应用(主要是前端)。

优缺点

  • 前后端耦合

    • 模板引擎加载只是将 jsp 的交互方式移植到 html 上,前端文件格式改变了,但是 jsp 中前后端耦合的缺点没有改变。
    • json 交互中,数据通过 js/jquery 动态加载在页面上,数据与页面进行分离,页面只是单纯用于展示。
  • 数据加载逻辑复用

    • 模板引擎的方式中,如果有很多相似的页面元素以及一样的数据返回格式,那只是复制粘贴大法了。
    • 在模板引擎的例子中,只需要定义一套数据加载模型,传入不同的页面元素 id 以及数据则能实现逻辑复用
  • 后端接口的复用
    因为我的学习路线的问题,所以我开发过安卓原生一段时间。

    • 模板引擎式的加载必须使用 webView 组件加载,且需另进行原生构建时接口也要另外构建。
    • json 交互,谷歌爸爸鼓励使用 json 进行交互(一年多前的事,现在不清楚了),且安卓原生内置 GJSON 进行 json 解析与构建,所以可以在原生以及跨平台的构建有很好的平衡。

对比

既然选择了 json 交互的方式,而 java 官方据我所知是没有内置对 json 的支持,Spring 在 Controller 的层面使用 RestContrller 注解实现对 json 的支持。
但是我个人强迫症很强,我对 Contrller(或者说是 Presenter)的定义是

  • 对用户访问的 url 作页面的映射
  • 对用户触发的事件进行数据的传递与返回

正是这两点的定义,我需要在 Service 层组合统一格式的结果返回到上层,所以需要第三方 json 支持。
可选择的 JSON 库有很多,GSON,FastJson,Jackson,根据对比,我选择为马老师充值一波。

需求拆分

我初步定义的需求主要有三个

  • Service 传递统一处理结果到上层
  • 无论是单一数据实体或者 List 型数据处理的结果是一样的
  • 处理过程是独立的,不依赖于实体类的支持

格式设计

在网上看过很多后端返回数据的格式,很多都是返回一个处理的 status 以及具体的数据,而这个 status 是根据 http 状态码进行设定的,因为这次时间比较紧,所以我就采用了这个方案。

{
    "status": "status",
    "object": {}}

代码设计

因为我希望 Controller 能直接拿到结果,所以构建结果的过程全放在 Result 类中。
而结果构建我主要分为两种:只有状态码 (通知处理结果) 以及具有返回结果(数据显示),而根据结果的个人也分为两种:单个数据以及 List 型数据。

实际代码

@Getter
@Slf4j
public class ResultSet {

    private JSONObject result;

    public ResultSet(){result=new JSONObject();
    }

    /**
     * 初始化状态码
     * @param status
     */
    public void initStatus(String status){result.put("status", status);
    }

    /**
     * 初始化状态码以及返回数据
     * @param status
     * @param obj
     */
    public void initData(String status,Object obj){initStatus(status);
        if(obj instanceof List){List list=(List)obj;
            JSONArray array=new JSONArray();
            for(Object object:list){array.add(putObjectToJSON(object));
            }
            result.put("object",array);
        }
        else {result.put("object",putObjectToJSON(obj));
        }
    }

    /**
     * 将单个 Object 放入 json 文件中
     * @param obj
     * @return
     */
    private JSONObject putObjectToJSON(Object obj){JSONObject result=new JSONObject();
        Field[] fields=obj.getClass().getDeclaredFields();
        for(Field field:fields){field.setAccessible(true);
            String fieldName=field.getType().getSimpleName();
            if(fieldName.equals("Department")||fieldName.equals("Job")){JSONObject tempJson=new JSONObject();
                try {Object tempObject = field.get(obj);
                    Field[] tempFields=tempObject.getClass().getDeclaredFields();
                    for(Field tempField:tempFields){tempField.setAccessible(true);
                        tempJson.put(tempField.getName(),tempField.get(tempObject));
                        tempField.setAccessible(false);
                    }
                } catch (IllegalAccessException e) {e.printStackTrace();
                }
                if(fieldName.equals("Department")){result.put("depart",tempJson);
                }
                else {result.put("job",tempJson);
                }
            }
            else {
                try {result.put(field.getName(),field.get(obj));
                } catch (IllegalAccessException e) {e.printStackTrace();
                }
            }
            field.setAccessible(false);
        }
        return result;
    }
}

代码思路

  1. Service 通过 initStatus/initData 传入数据 / 状态码进行对象的生成
  2. Controller 通过 result 的 getter 方法获取处理结果
  3. 单个数据以及 List 数据的处理

    1. 单个对象直接通过 putObjectToJSON 进行处理
    2. List 数据通过对象类型判断,向下转型,遍历元素形成 JSONArray 进行处理,对元素处理的方法也是采用 putObjectToJSON
  4. 嵌套对象的处理

    public class Employee {
    
       private int id;
    
       private Department depart;
    
       private Job job;
    
       private String name;
    
        ..................
    }
    1. 通过反射获取对象的所有成员变量类型以及对应的值
    2. 遇到上述 bean 类含有嵌套自定义对象时,递归生成 json 文件加入到结果 json 中

结果演示

​(左为单 object 型,右为 List 型)

不足之处

  1. 状态码的设置应该采用枚举类的赋值,能更好的约束返回的状态码
  2. 在对象转换方面,应该采用配置扫描的方式。在配置文件中写入 bean 的包所在,在嵌套对象转换时通过扫描配置文件的信息判断
  3. 在嵌套对象的转换方面,只是做了一层的嵌套转换,更多层的没有考虑到,之后会再重构的
  4. 对异常处理方面,只是简单的输出错误信息。应该对错误信息进行进一步的处理

后记

因为这次时间比较赶,从项目的立项到成品的建立花了 5 天时间,所以注意到很多细节,但是没有去处理。
有想过之后有时间的话将这个工具类的细节完善起来,形成 jar 包供自己或者供开源。

相关连接

这只是后台对结果的统一处理,我另外写了一篇文章:JSON 工具类的构建(前端版本)),配合使用效果更佳哦~

本文首发于 cartoon 的博客
转载请注明出处:https://cartoonyu.github.io/cartoon-blog/post/json/json 工具类的构建后端版本 /

退出移动版