检索要在MySql中上载的序列化JFrame



我在Jython中有一个扩展Java Swing JFrame的对象。我的目标是序列化它,以便将其保存在MySql上,查询数据库,反序列化它,并查看JFrame,与反序列化前完全一样(填写所有字段)

老实说,我不知道从哪里开始。我无法想象序列化-保存到数据库。我猜序列化的JFrame可能是MySql上的bloblongblobbit类型

目前,我已经用我以前很少的学术知识在java中进行了一个关于对象序列化的本地实验,结果很差:

def saveArt(self, e):
v = Vector()
v.add(self) # self = JFrame in question
out = ObjectOutputStream(BufferedOutputStream(FileOutputStream("prova.dat")))
out.writeObject(v)
out.close()

我所做的只是将帧放在Java向量中,并将其保存到文件中,但我得到了以下错误:

Exception in thread "AWT-EventQueue-0"  at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.writeObject(Unknown Source)
at java.util.concurrent.ConcurrentHashMap.writeObject(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at java.io.ObjectStreamClass.invokeWriteObject(Unknown Source)
at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.writeObject(Unknown Source)
at java.util.concurrent.ConcurrentHashMap.writeObject(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at java.io.ObjectStreamClass.invokeWriteObject(Unknown Source)
at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.writeObject(Unknown Source)
at javax.swing.event.EventListenerList.writeObject(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at java.io.ObjectStreamClass.invokeWriteObject(Unknown Source)
at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
at java.io.ObjectOutputStream.defaultWriteObject(Unknown Source)
at javax.swing.JComponent.writeObject(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at java.io.ObjectStreamClass.invokeWriteObject(Unknown Source)
at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.writeObject(Unknown Source)
at java.awt.AWTEventMulticaster.saveInternal(Unknown Source)
at java.awt.AWTEventMulticaster.saveInternal(Unknown Source)
at java.awt.AWTEventMulticaster.saveInternal(Unknown Source)
at java.awt.AWTEventMulticaster.saveInternal(Unknown Source)
at java.awt.AWTEventMulticaster.saveInternal(Unknown Source)
at java.awt.AWTEventMulticaster.saveInternal(Unknown Source)
at java.awt.AWTEventMulticaster.saveInternal(Unknown Source)
at java.awt.AWTEventMulticaster.saveInternal(Unknown Source)
at java.awt.AWTEventMulticaster.save(Unknown Source)
at java.awt.Component.writeObject(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at java.io.ObjectStreamClass.invokeWriteObject(Unknown Source)
at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.writeArray(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.access$300(Unknown Source)
at java.io.ObjectOutputStream$PutFieldImpl.writeFields(Unknown Source)
at java.io.ObjectOutputStream.writeFields(Unknown Source)
at java.util.Vector.writeObject(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at java.io.ObjectStreamClass.invokeWriteObject(Unknown Source)
at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.writeObject(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
java.io.NotSerializableException: java.io.NotSerializableException: org.python.core.packagecache.SysPackageManager

这个实验并不重要,因为它肯定不是最终目标。这只是为了弄清楚我是否可以在本地序列化它

最终目标是将其保存在MySql数据库中,并按照保存的方式提取

所以我需要了解3件事:

  1. 如何用Jython序列化JFrame(假设序列化是为数据库"打包"已填充JFrame的最佳方式,如果有更好的方法,请不要犹豫)
  2. 在Mysql上设置什么样的数据(假设Mysql是实现这一点的完美dbms,如果有更好的技术,请毫不犹豫地说出来!)以及是否需要进行特定的查询
  3. 如何对它进行反序列化,以完全按照我离开它的方式查看它(假设反序列化是检索JFrame的最佳方式)

提前非常感谢我的救世主(如果有的话)

首先,Java序列化在最好的情况下是个坏主意。Java SE的安全编码指南说";注意:不可信数据的反序列化本质上是危险的,应该避免"不幸的是,文本不再是红色的。

在这种情况下,问题就更大了,因为数据只会在数据库中的一个blob中,而Swing不能保证版本之间的串行兼容性(甚至可能是更新?)。

顺便说一句:从stracktrace来看,问题对象是SysPackageManager,它位于ConcurrentHashMap本身和ConcurrentHashMap本身的某个位置,您可能不想保留它。

将系统属性sun.io.serialization.extendedDebugInfo(可能更改)设置为true将提供有关如何引用对象的更多信息。

显然JFrame太多了。有更好的方法来存储数据。

Tom介绍了错误的原因以及进一步调试的可能方法

我将尝试用java代码详细解决您提出的3件事:

  1. 如何序列化?-回答如下
  2. 使用哪个数据类型创建mysql列来存储这些数据?-在mysql的情况下,我会说中型blob,blob可能太小,而longblob可能太大。我也使用了长文本,它按预期工作,没有任何问题,但它确实很长,可以解释为什么是blob而不是文本字段。这个stackoverflow的答案可能会带来更多的启发——在mysqldb中应该使用什么列类型来存储序列化数据
  3. 如何反序列化和使用?-回答如下

移动到答案:你可以通过几个步骤来实现这一点
  1. 创建JFrame

  2. 将java对象序列化到mysql数据库-这就像一样简单

    preparedStatement.setObject(jframe_object_to_save_to_database);
    pstmt.executeUpdate();
    
  3. 从mysql数据库中解序列化java对象并将其转换为JFrame对象-这不是那么简单,但也不是那么复杂,我的方法将包括4个步骤,如下面的

    3.a.只需将列值读取为字节数组
    3.b.创建我们从数据库中获得的字节数组的ByteArrayInputStream对象
    3.c.从ByteArrayInput Stream创建ObjectInputStream
    3.d.使用ObjectInputStream.readObject()方法获得解序列化的对象

    以下代码片段涵盖了这些步骤

    byte[] buf = rs.getBytes(1);
    ObjectInputStream objectIn = null;
    if (buf != null)
    objectIn = new ObjectInputStream(new ByteArrayInputStream(buf));
    Object deSerializedObject = objectIn.readObject();
    
  4. 现在,由于我们已经准备好了反序列化对象(从3.d开始),您可以很容易地将其解析为JFrame对象,并在需要时使用它

Jframe deSerializedObject = (JFrame) objectIn.readObject();

下面是我的完整java实现,这是一个简单的JFrame与mysql数据库的工作代码,请按照我在代码中作为注释编写的步骤1到步骤5进行操作,并阅读我在deSerializeJavaObjectFromDB方法中提到的注意事项

import java.awt.FlowLayout;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
import java.util.Vector;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class SerializeToDatabase {
private static final String SQL_CREATE_TABLE = "create table if not exists serialized_java_objects (object_name varchar(1000), serialized_object blob)";
private static final String SQL_SERIALIZE_OBJECT = "INSERT INTO serialized_java_objects(object_name, serialized_object) VALUES (?, ?)";
private static final String SQL_DESERIALIZE_OBJECT = "SELECT serialized_object FROM serialized_java_objects limit 1";
public static void createTable(Connection connection) throws SQLException {
connection.createStatement().executeUpdate(SQL_CREATE_TABLE);
}

public static void serializeJavaObjectToDB(Connection connection,
Object objectToSerialize) throws SQLException {
PreparedStatement pstmt = connection
.prepareStatement(SQL_SERIALIZE_OBJECT);
// just setting the class name
pstmt.setString(1, objectToSerialize.getClass().getName());
pstmt.setObject(2, objectToSerialize);
pstmt.executeUpdate();
pstmt.close();

System.out.println("Java object serialized to database. Object: " + objectToSerialize);
}
/**
* To de-serialize a java object from database
*
* @throws SQLException
* @throws IOException
* @throws ClassNotFoundException
*/
public static Object deSerializeJavaObjectFromDB(Connection connection) throws SQLException, IOException,
ClassNotFoundException {
PreparedStatement pstmt = connection.prepareStatement(SQL_DESERIALIZE_OBJECT);
ResultSet rs = pstmt.executeQuery();
rs.next();
//NOTE - below is the most basic way of retrieving data from result set, works perfect for general data 
//Object object = rs.getObject(1);
//NOTE - below is the way how we need to implement to retrieve serialized objects from resultset
byte[] buf = rs.getBytes(1);
ObjectInputStream objectIn = null;
if (buf != null)
objectIn = new ObjectInputStream(new ByteArrayInputStream(buf));
Object deSerializedObject = objectIn.readObject();
rs.close();
pstmt.close();
System.out.println("Java object de-serialized from database. Object: "
+ deSerializedObject + " Classname: "
+ deSerializedObject.getClass().getName());

return deSerializedObject;
}
public static Connection getMySqlConnection(String ipAddr, String portNumber, String db, String userName, String password) throws SQLException {

Connection mysqlConn = null;

Properties properties = new Properties();
properties.put("user", userName);
properties.put("password", password);

mysqlConn = DriverManager.getConnection("jdbc:mysql://"+ipAddr+":"+portNumber+"/"+db, properties);
return mysqlConn;
}

/**
* Serialization and de-serialization of java object from mysql
*
* @throws ClassNotFoundException
* @throws SQLException
* @throws IOException
*/
public static void main(String args[]) throws ClassNotFoundException,
SQLException, IOException {

//step 1 - create mysql connection
Connection connection = getMySqlConnection("192.168.1.119", "3306", "xxx", "xxx", "xxx");
//step 2 - create JFrame
JFrame frame = new JFrame("JFrame Example");  
JPanel panel = new JPanel();  
panel.setLayout(new FlowLayout());  
JLabel label = new JLabel("JFrame By Example");  
JButton button = new JButton();  
button.setText("Button");  
panel.add(label);  
panel.add(button);  
frame.add(panel);  
frame.setSize(200, 300);  
frame.setLocationRelativeTo(null);  
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//uncomment below line if you want to see the JFrame before persisting data
//frame.setVisible(true);
//step 3 - create table
createTable(connection);

//step 4 - serializing java object to mysql database
serializeJavaObjectToDB(connection, frame);
//step 5 - de-serializing java object from mysql database and converting it into JFrame object
JFrame objFromDatabase = (JFrame) deSerializeJavaObjectFromDB(connection);
//setVisible(true) will show the JFrame as is, what ever we have persisted
objFromDatabase.setVisible(true);

//finally close the connection
connection.close();
}
}

注1:我没有jython设置,所以我无法在这里提供python/jython代码片段。但我试图用纯java来回答这个问题,我认为你可以很容易地将其与jython中的需求联系起来(因为我使用的类没有变化)

注2:我不想争论序列化的持久性是对是错,这取决于应用程序的类型、用户的类型、项目的类型和许多其他场景。你是案件的最佳法官

注3:这篇文章帮助我更好地回答了这个问题-https://javapapers.com/core-java/serialize-de-serialize-java-object-from-database/

最新更新