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

相关文章

Java如何用乘号来重复字符串的功能

《Java如何用乘号来重复字符串的功能》:本文主要介绍Java使用乘号来重复字符串的功能,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Java乘号来重复字符串的功能1、利用循环2、使用StringBuilder3、采用 Java 11 引入的String.rep

使用animation.css库快速实现CSS3旋转动画效果

《使用animation.css库快速实现CSS3旋转动画效果》随着Web技术的不断发展,动画效果已经成为了网页设计中不可或缺的一部分,本文将深入探讨animation.css的工作原理,如何使用以及... 目录1. css3动画技术简介2. animation.css库介绍2.1 animation.cs

Java进行日期解析与格式化的实现代码

《Java进行日期解析与格式化的实现代码》使用Java搭配ApacheCommonsLang3和Natty库,可以实现灵活高效的日期解析与格式化,本文将通过相关示例为大家讲讲具体的实践操作,需要的可以... 目录一、背景二、依赖介绍1. Apache Commons Lang32. Natty三、核心实现代

SpringBoot实现接口数据加解密的三种实战方案

《SpringBoot实现接口数据加解密的三种实战方案》在金融支付、用户隐私信息传输等场景中,接口数据若以明文传输,极易被中间人攻击窃取,SpringBoot提供了多种优雅的加解密实现方案,本文将从原... 目录一、为什么需要接口数据加解密?二、核心加解密算法选择1. 对称加密(AES)2. 非对称加密(R

基于Go语言实现Base62编码的三种方式以及对比分析

《基于Go语言实现Base62编码的三种方式以及对比分析》Base62编码是一种在字符编码中使用62个字符的编码方式,在计算机科学中,,Go语言是一种静态类型、编译型语言,它由Google开发并开源,... 目录一、标准库现状与解决方案1. 标准库对比表2. 解决方案完整实现代码(含边界处理)二、关键实现细

python通过curl实现访问deepseek的API

《python通过curl实现访问deepseek的API》这篇文章主要为大家详细介绍了python如何通过curl实现访问deepseek的API,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编... API申请和充值下面是deepeek的API网站https://platform.deepsee

SpringBoot实现二维码生成的详细步骤与完整代码

《SpringBoot实现二维码生成的详细步骤与完整代码》如今,二维码的应用场景非常广泛,从支付到信息分享,二维码都扮演着重要角色,SpringBoot是一个非常流行的Java基于Spring框架的微... 目录一、环境搭建二、创建 Spring Boot 项目三、引入二维码生成依赖四、编写二维码生成代码五

C语言中的常见进制转换详解(从二进制到十六进制)

《C语言中的常见进制转换详解(从二进制到十六进制)》进制转换是计算机编程中的一个常见任务,特别是在处理低级别的数据操作时,C语言作为一门底层编程语言,在进制转换方面提供了灵活的操作方式,今天,我们将深... 目录1、进制基础2、C语言中的进制转换2.1 从十进制转换为其他进制十进制转二进制十进制转八进制十进

Pandas进行周期与时间戳转换的方法

《Pandas进行周期与时间戳转换的方法》本教程将深入讲解如何在pandas中使用to_period()和to_timestamp()方法,完成时间戳与周期之间的转换,并结合实际应用场景展示这些方法的... 目录to_period() 时间戳转周期基本操作应用示例to_timestamp() 周期转时间戳基

MyBatisX逆向工程的实现示例

《MyBatisX逆向工程的实现示例》本文主要介绍了MyBatisX逆向工程的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学... 目录逆向工程准备好数据库、表安装MyBATisX插件项目连接数据库引入依赖pom.XML生成实体类、