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

相关文章

C++使用栈实现括号匹配的代码详解

《C++使用栈实现括号匹配的代码详解》在编程中,括号匹配是一个常见问题,尤其是在处理数学表达式、编译器解析等任务时,栈是一种非常适合处理此类问题的数据结构,能够精确地管理括号的匹配问题,本文将通过C+... 目录引言问题描述代码讲解代码解析栈的状态表示测试总结引言在编程中,括号匹配是一个常见问题,尤其是在

Java实现检查多个时间段是否有重合

《Java实现检查多个时间段是否有重合》这篇文章主要为大家详细介绍了如何使用Java实现检查多个时间段是否有重合,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录流程概述步骤详解China编程步骤1:定义时间段类步骤2:添加时间段步骤3:检查时间段是否有重合步骤4:输出结果示例代码结语作

Java中String字符串使用避坑指南

《Java中String字符串使用避坑指南》Java中的String字符串是我们日常编程中用得最多的类之一,看似简单的String使用,却隐藏着不少“坑”,如果不注意,可能会导致性能问题、意外的错误容... 目录8个避坑点如下:1. 字符串的不可变性:每次修改都创建新对象2. 使用 == 比较字符串,陷阱满

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

IDEA编译报错“java: 常量字符串过长”的原因及解决方法

《IDEA编译报错“java:常量字符串过长”的原因及解决方法》今天在开发过程中,由于尝试将一个文件的Base64字符串设置为常量,结果导致IDEA编译的时候出现了如下报错java:常量字符串过长,... 目录一、问题描述二、问题原因2.1 理论角度2.2 源码角度三、解决方案解决方案①:StringBui

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

如何通过Python实现一个消息队列

《如何通过Python实现一个消息队列》这篇文章主要为大家详细介绍了如何通过Python实现一个简单的消息队列,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录如何通过 python 实现消息队列如何把 http 请求放在队列中执行1. 使用 queue.Queue 和 reque

Python如何实现PDF隐私信息检测

《Python如何实现PDF隐私信息检测》随着越来越多的个人信息以电子形式存储和传输,确保这些信息的安全至关重要,本文将介绍如何使用Python检测PDF文件中的隐私信息,需要的可以参考下... 目录项目背景技术栈代码解析功能说明运行结php果在当今,数据隐私保护变得尤为重要。随着越来越多的个人信息以电子形