JFinal中如何实现反序列化----JSON字符串向Model对象转换

2024-02-08 10:20

本文主要是介绍JFinal中如何实现反序列化----JSON字符串向Model对象转换,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

   需求: 将客户端传来的requestbody反序列化成对应的Model对象。

一、反序列化--驼峰命名

1、fastjson实现

   JFinal中没有提供反序列化的方法,因为大多数情况下,可以直接通过jar包进行转换,如利用fastjson,我们可以通过如下方式进行转换:

    JSON.parseArray(String jsonString, Class<T> class);
2、举个例子

  现有一个实体类:Book

@Data
pubilc class Book{private String bookName;private int bookPrice;
}

  将传过来的单个json数据转成对象:

String jsonStr = "{\"booktName\":\"钢铁是怎样练成的",\"bookPrice\":38.8}";
JSONArray jsonArray = JSON.parseArray(jsonStr);
Book book= (Book ) JSONObject.parseArray(jsonArray.toJSONString(), Book.class);

  将传过来的多个json数据转成对象:

String bookStr = "{\"bookList\":[{\"bookName\":\"钢铁是怎样炼成的\",\"bookPrice\":38.8},{\"bookName\":\"废柴是怎样堕落的\",\"bookPrice\":18.8}]}";
JSONObject bookJson = JSON.parseObject(bookStr );
JSONArray bookArray = bookJson .getJSONArray("bookList");
//第一种解析方式:直接解析为对象list
List<Book> booksList= JSONObject.parseArray(bookArray .toJSONString(), Book.class);

    但是如果在JFinal中这样写,编译的过程中他不会报错,但你会发现他存进去的都是空值,也就是说他在做类型转换的时候虽然识别到了这个Model,但是并不能和数据库表里的字段对应上。这是因为在数据表中,采用的是下划线"_"连接命名方式,而这种方法实际上是适用于驼峰命名的方式。

   为什么会造成这种情况呢?因为在jfinal里 Model中的getter、setter方法是按照驼峰命名的规则来生成,这时json中键值若使用数据库列名,当使用fastjson序列化时,我们会得到无法找到对应setter,从而也就无法更新其值。

接下来介绍如何解决:

二、反序列化--下划线"_"连接命名

 Object bookList= jsonObject.get("bookList");String jsonString = JSON.toJSONString( bookList, SerializerFeature.WriteMapNullValue);     List<Book> contactNoteList = parseArrayToModel(jsonString,Book.class);for (Booklist: contactNoteList) {list.set("head_id",book.get("id")).save();}

  这里设置SerializerFeature.WriteMapNullValue是因为,当传入的json以保留null值的键

//总体而言,此方法接受一个JSON数组字符串,解析它,并将每个JSON对象转换为指定模型类型的实例。它根据JSON对象中的键和值填充模型的属性,并返回这些填充好的模型的列表。public <T extends Model<T>> List<T> parseArrayToModel(String jsonString, Class<T> type) throws Exception {//初始化:List<T> list = new ArrayList<T>();JSONArray jsonArr = JSON.parseArray(jsonString);Table table = TableMapping.me().getTable(type); //使用TableMapping类的方法获取与给定模型类型相关联的表//模型解析循环:for (int i = 0; i < jsonArr.size(); i++) {T model = type.newInstance();//使用模型类型(T)的默认构造函数创建模型的新实例。JSONObject jsonObj = jsonArr.getJSONObject(i);//属性解析循环:for (String key : jsonObj.keySet()) {  //遍历JSON对象中的每个键。Class<?> colType = table.getColumnType(key);//从关联表中获取当前属性键的列类型。if (colType == null) { //如果未找到列类型(表示缺少属性),则抛出异常。throw new ActiveRecordException("The model attribute " + key + " is not exists.");}//值转换和模型填充:try {String paraValue = jsonObj.get(key) != null ? jsonObj.getString(key) : null;Object value = paraValue != null ? OpenJFinalMethod.convert(colType, paraValue) : null;  //尝试使用OpenJFinalMethod.convert方法将与当前键关联的JSON值转换为适当的类型。model.set(key, value); //使用model.set方法设置模型中的属性值。} catch (Exception e) {throw new RuntimeException("Can not convert parameter: " + key, e);}}//模型添加到列表:list.add(model); //返回包含解析后的模型的列表。}//返回语句:return list; //返回包含解析后的模型的列表。}

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.text.ParseException;
import java.text.SimpleDateFormat;/*** Convert String to other type object.*/
public class TypeConverter {private static Logger logger = LoggerFactory.getLogger(DocumentApiUtil.class);private static final String timeStampPattern = "yyyy-MM-dd HH:mm:ss";private static final String datePattern = "yyyy-MM-dd";private static final int dateLen = datePattern.length();/*** test for all types of mysql** 表单提交测试结果:* 1: 表单中的域,就算不输入任何内容,也会传过来 "", 也即永远不可能为 null.* 2: 如果输入空格也会提交上来* 3: 需要考 model中的 string属性,在传过来 "" 时是该转成 null还是不该转换,*    我想, 因为用户没有输入那么肯定是 null, 而不该是 ""** 注意: 1:当type参数不为String.class, 且参数s为空串blank的情况,*       此情况下转换结果为 null, 而不应该抛出异常*      2:调用者需要对被转换数据做 null 判断,参见 ModelInjector 的两处调用*/public static final Object convert(Class<?> type, String s) throws ParseException {// mysql type: varchar, char, enum, set, text, tinytext, mediumtext, longtextif (type == String.class) {return ("".equals(s) ? null : s);	// 用户在表单域中没有输入内容时将提交过来 "", 因为没有输入,所以要转成 null.}s = s.trim();if ("".equals(s)) {	// 前面的 String跳过以后,所有的空字符串全都转成 null,  这是合理的return null;}// 以上两种情况无需转换,直接返回, 注意, 本方法不接受null为 s 参数(经测试永远不可能传来null, 因为无输入传来的也是"")// mysql type: int, integer, tinyint(n) n > 1, smallint, mediumintif (type == Integer.class || type == int.class) {return Integer.parseInt(s);}// mysql type: bigintif (type == Long.class || type == long.class) {return Long.parseLong(s);}// java.util.Date 类型专为传统 java bean 带有该类型的 setter 方法转换做准备,万不可去掉// 经测试 JDBC 不会返回 java.util.Data 类型。java.sql.Date, java.sql.Time,java.sql.Timestamp 全部直接继承自 java.util.Data, 所以 getDate可以返回这三类数据if (type == java.util.Date.class) {if (s.length() > dateLen) {	// if (x < timeStampLen) 改用 datePattern 转换,更智能// Timestamp format must be yyyy-mm-dd hh:mm:ss[.fffffffff]// return new java.util.Date(java.sql.Timestamp.valueOf(s).getTime());	// error under jdk 64bit(maybe)return new SimpleDateFormat(timeStampPattern).parse(s);}else {// return new java.util.Date(java.sql.Date.valueOf(s).getTime());	// error under jdk 64bitreturn new SimpleDateFormat(datePattern).parse(s);}}// mysql type: date, yearif (type == java.sql.Date.class) {if (s.length() > dateLen) {	// if (x < timeStampLen) 改用 datePattern 转换,更智能// return new java.sql.Date(java.sql.Timestamp.valueOf(s).getTime());	// error under jdk 64bit(maybe)return new java.sql.Date(new SimpleDateFormat(timeStampPattern).parse(s).getTime());}else {// return new java.sql.Date(java.sql.Date.valueOf(s).getTime());	// error under jdk 64bitreturn new java.sql.Date(new SimpleDateFormat(datePattern).parse(s).getTime());}}// mysql type: timeif (type == java.sql.Time.class) {return java.sql.Time.valueOf(s);}// mysql type: timestamp, datetimeif (type == java.sql.Timestamp.class) {if (s.length() > dateLen) {return java.sql.Timestamp.valueOf(s);}else {return new java.sql.Timestamp(new SimpleDateFormat(datePattern).parse(s).getTime());}}// mysql type: real, doubleif (type == Double.class || type == double.class) {return Double.parseDouble(s);}// mysql type: floatif (type == Float.class || type == float.class) {return Float.parseFloat(s);}// mysql type: bit, tinyint(1)if (type == Boolean.class || type == boolean.class) {String value = s.toLowerCase();if ("1".equals(value) || "true".equals(value)) {return Boolean.TRUE;}else if ("0".equals(value) || "false".equals(value)) {return Boolean.FALSE;}else {throw new RuntimeException("Can not parse to boolean type of value: " + s);}}// mysql type: decimal, numericif (type == java.math.BigDecimal.class) {return new java.math.BigDecimal(s);}// mysql type: unsigned bigintif (type == java.math.BigInteger.class) {return new java.math.BigInteger(s);}// mysql type: binary, varbinary, tinyblob, blob, mediumblob, longblob. I have not finished the test.if (type == byte[].class) {return s.getBytes();}throw new RuntimeException(type.getName() + " can not be converted, please use other type of attributes in your model!");}}

这篇关于JFinal中如何实现反序列化----JSON字符串向Model对象转换的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/690728

相关文章

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略 1. 特权模式限制2. 宿主机资源隔离3. 用户和组管理4. 权限提升控制5. SELinux配置 💖The Begin💖点点关注,收藏不迷路💖 Kubernetes的PodSecurityPolicy(PSP)是一个关键的安全特性,它在Pod创建之前实施安全策略,确保P

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、

C++——stack、queue的实现及deque的介绍

目录 1.stack与queue的实现 1.1stack的实现  1.2 queue的实现 2.重温vector、list、stack、queue的介绍 2.1 STL标准库中stack和queue的底层结构  3.deque的简单介绍 3.1为什么选择deque作为stack和queue的底层默认容器  3.2 STL中对stack与queue的模拟实现 ①stack模拟实现

基于51单片机的自动转向修复系统的设计与实现

文章目录 前言资料获取设计介绍功能介绍设计清单具体实现截图参考文献设计获取 前言 💗博主介绍:✌全网粉丝10W+,CSDN特邀作者、博客专家、CSDN新星计划导师,一名热衷于单片机技术探索与分享的博主、专注于 精通51/STM32/MSP430/AVR等单片机设计 主要对象是咱们电子相关专业的大学生,希望您们都共创辉煌!✌💗 👇🏻 精彩专栏 推荐订阅👇🏻 单片机