[疯狂Java]JDBC:用blob处理多媒体类型数据

1. JDBC导入Blob类型数据:

    1) Blob即Binary Long Object的缩写,即二进制长对象,常用于存储大型文件,比如图片、音视频等;

    2) 由于在SQL中无法表示blob常量,因此就不能用Statement导入到数据库,但幸好可以用PreparedStatement导入数据库:

         i. PreparedStatement可以用通配符?来表示要插入的blob常量;

         ii. 然后使用PreparedStatement的setBinaryStream将blob类型数据插入到通配符?的位置:

void PreparedStatement.setBinaryStream(int parameterIndex, java.io.InputStream x[, int length]);

             a. 这里要求导入的blob数据以输入流的形式提交给数据库;

             b. 而一般要导入的数据都是保存在磁盘上的,因此通常会创建目标文件的文件节点流作为该参数传入;

             c. 例如:pstmt.setBinaryStream(1, new FileInputStream(new File("xxx.mp3")));

             d. 还有一个可选参数length,即流中的字节数;

         iii. 最后提交insert into语句完成blob类型数据的导入;

    3) 从数据库读取Blob类型数据:

         i. ResultSet直接提供了getBlob方法:Blob getBlob(int columnIndex | String columnLabel);

         ii. 可以看到Java直接提供了Blob类型;

    4) Blob类型常用方法:

         i. byte[] Blob.getBytes(long pos, int length); // 从blob对象的第pos个字节开始,复制出length个字节的byte数组返回,blob变量的第一个字节的位置是1不是0!!!

         ii. long Blob.length(); // blob变量中共有多少个字节


2. 示例:图片数据库交互

    1) 是一个Swing界面,右侧是一个图片名列表,显示当前数据库中存在的图片名,左侧是一个图片显示框,双击列表中的图片名就可以在显示框中显示图片;

    2) 左下侧是一个文件按钮,点击可以在Windows资源管理内选择图片格式的文件,选中后图片的路径会显示在一个不可编辑的文本框内;

    3) 点击upload按钮,可以将选中的图片文件导入到数据库,同时更新右侧列表中的内容;

首先需要在select_test数据库中加一张保存图片的表

create table img_table
(
    img_id int auto_increment primary key,
    img_name varchar(255),
    img_data mediumblob
);

public class ImageHolder { // 封装图片名和ID
	private int id;
	private String name;
	
	public ImageHolder() {}
	
	public ImageHolder(int id, String name) {
		this.id = id;
		this.name = name;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return name;
	}
}

public class ExtensionFileFilter extends FileFilter { // 自行对FileFilter进行扩展
	private String desc = ""; // 过滤器的描述文本
	private ArrayList<String> exts = new ArrayList<>();
	
	@Override
	public boolean accept(File f) { // 判断该过滤器是否该接受该文件
		// TODO Auto-generated method stub
		if (f.isDirectory()) {
			return true; // 目录必定接受
		}
		
		String name = f.getName().toLowerCase();
		for (String ext: exts) { // 如果文件名以指定后缀结尾就接受
			if (name.endsWith(ext)) {
				return true;
			}
		}
		
		return false;
	}
	
	@Override
	public String getDescription() {
		// TODO Auto-generated method stub
		return desc;
	}
	
	public void addExt(String ext) { // 向过滤器中添加扩展名
		if (!ext.startsWith(".")) { // 给定的扩展名全部统一成以.开头的小写形式
			ext = "." + ext;
			exts.add(ext.toLowerCase());
		}
	}
	
	public void addExts(String[] exts) { // 用扩展名列表来添加扩展名
		for (String ext: exts) {
			addExt(ext);
		}
	}

	public String getDesc() {
		return desc;
	}

	public void setDesc(String desc) { // 设置过滤器的描述文本
		this.desc = desc;
	}
	
}

public class BlobTest {
	
	// Connection
	private static Connection conn;
	private static PreparedStatement pstmtInsertImg;
	private static PreparedStatement pstmtQueryImg;
	private static PreparedStatement pstmtQueryAllImg;
	
	static { // 仅用来初始化连接资源
		try {
			Properties props = new Properties();
			props.load(new FileInputStream("mysql.ini"));
			String driver = props.getProperty("driver");
			String url = props.getProperty("url");
			String user = props.getProperty("user");
			String pass = props.getProperty("pass");
			Class.forName(driver);
			
			conn = DriverManager.getConnection(url, user, pass);
			pstmtInsertImg = conn.prepareStatement("insert into img_table values(null, ?, ?)", Statement.RETURN_GENERATED_KEYS);
			pstmtQueryImg = conn.prepareStatement("select img_data from img_table where img_id = ?");
			pstmtQueryAllImg = conn.prepareStatement("select img_id, img_name from img_table");
		}
		catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	// GUI
	private JFrame jf;
		private JPanel jpLeft;
			private JLabel jlImg;
			private JPanel jp;
				private JTextField jtFilePath;
				private JButton jbBrowser;
				private JButton jbUpload;
		private JList<ImageHolder> jliImgList;
			private DefaultListModel<ImageHolder> imgModel;
			
	// 文件选择器和过滤器
	private JFileChooser chooser;
	private ExtensionFileFilter filter;
			
	public void initGUI() {
		jf = new JFrame("Pics Manager");
			jpLeft = new JPanel(); jf.add(jpLeft); jpLeft.setLayout(new BorderLayout());
				jlImg = new JLabel(); jpLeft.add(new JScrollPane(jlImg));
				jp = new JPanel(); jpLeft.add(jp, BorderLayout.SOUTH);
					jtFilePath = new JTextField(26); jp.add(jtFilePath); 
							jtFilePath.setEditable(false); // 文件路径编辑框只能显示不能编辑
					jbBrowser = new JButton("..."); jp.add(jbBrowser);
					jbUpload = new JButton("upload"); jp.add(jbUpload);
			imgModel = new DefaultListModel<>(); jliImgList = new JList<>(imgModel); jf.add(new JScrollPane(jliImgList), BorderLayout.EAST);
					jliImgList.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); // 列表只能单选(因为这里一次只能显示一张图片)
					jliImgList.setFixedCellWidth(160);
					
		jf.setSize(620, 400);
		jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		jf.setVisible(true);
	}

	public void showImage(int id) throws SQLException { // 给定图片ID在图片显示界面中显示出来
		pstmtQueryImg.setInt(1, id); // 拿ID去查
		try (ResultSet rs = pstmtQueryImg.executeQuery()) {
			if (rs.next()) {
				Blob img = rs.getBlob(1); // 获取blob图片
				ImageIcon icon = new ImageIcon(img.getBytes(1L, (int)img.length())); // 转换成Icon类型
				jlImg.setIcon(icon); // 加入到静态标签中
			}
		}
	}
	
	public void updateListModel() throws SQLException { // 更新列表模型
		try (ResultSet rs = pstmtQueryAllImg.executeQuery()) { // 重新查询
			imgModel.clear(); // 先清空原来的模型
			while (rs.next()) { // 然后再逐个添加ImageHolder(从数据库取出后包装)
				imgModel.addElement(new ImageHolder(rs.getInt(1), rs.getString(2)));
			}
		}
	}
	
	public void upload(String fileName) { // 将指定图片上传到数据库中
		// 截取路径和扩展名作为数据库中图片的名称
		String imgName = fileName.substring(fileName.lastIndexOf('\\') + 1, fileName.lastIndexOf('.'));
		
		File f = new File(fileName); // 为指定的图片(保存在磁盘中)创建一个节点
		try (InputStream is = new FileInputStream(f)) { // 获取一个节点流
			pstmtInsertImg.setString(1, imgName);
			pstmtInsertImg.setBinaryStream(2, is, (int)f.length()); // 作为输出流输出给数据库
			int affect = pstmtInsertImg.executeUpdate();
			if (affect == 1) {
				updateListModel(); // 成功上传则应该立即更新列表(列表显示的是当前数据库中的图片)
			}
		}
		catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public void init() throws SQLException {
		// 初始化文件选择器
		chooser = new JFileChooser("."); // 默认从当前路径开始查找
		filter = new ExtensionFileFilter();
		filter.addExts(new String[] {"jpg", "jpeg", "gif", "png"}); // 设置文件类型
		filter.setDesc("Image file(*.jpg, *jpeg, *.gif, *.png)"); // 设置过滤器描述信息
		chooser.addChoosableFileFilter(filter); // 为文件选择器绑定过滤器
		chooser.setAcceptAllFileFilterUsed(false); // 将文件选择器中“显示所有文件”的选项关闭
		
		// 初始化GUI界面
		initGUI();
		updateListModel(); // 先用数据库已有的图片初始化列表模型
				
		// 注册监听器
		jbBrowser.addActionListener(e -> { // 打开文件选择器对话框选择文件
			int res = chooser.showDialog(jf, "Select an image to upload");
			if (res == JFileChooser.APPROVE_OPTION) {
				jtFilePath.setText(chooser.getSelectedFile().getPath()); // 将选中的文件路径更新至路径编辑框中
			}
		});
		jbUpload.addActionListener(e -> {
			if (jtFilePath.getText().trim().length() > 0) {
				upload(jtFilePath.getText());
				jtFilePath.setText(""); // 上传完毕后编辑框清空
			}
		});
		jliImgList.addMouseListener(new MouseAdapter() {

			@Override
			public void mouseClicked(MouseEvent e) {
				// TODO Auto-generated method stub
				if (e.getClickCount() >= 2) { // 双击选中列表中的文件则从数据库载入该图片并显示
					ImageHolder selected = (ImageHolder)jliImgList.getSelectedValue();
					try {
						showImage(selected.getId()); // 选中后直接显示
					}
					catch (Exception ex) {
						ex.printStackTrace();
					}
				}
			}
			
		});
	}
	
	public static void main(String[] args) throws SQLException {
		// TODO Auto-generated method stub
		new BlobTest().init();
	}

}

mysql.ini

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/select_test
user=root
pass=1234


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值