一、问题描述
- 将用户在网页上上传的图片进行编码后,分别以二进制和base64格式存入数据库
- 将数据库中查询到的信息解码后显示在页面中
二、问题解决
说明:
本篇文章使用的技术栈为 spring boot + mybatis-plus +thymeleaf
1. 前后端和数据库代码
前端上传页面
<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div class="ibox-content">
<form th:action="@{/add_picture_post}" enctype="multipart/form-data" method="post">
<label class="font-bold">选择二进制存储文件</label>
<input type="file" class="form-control" name="binPto" style="width: 285px;margin: 0 auto"> <br/>
<label class="font-bold">选择base64存储文件</label>
<input type="file" class="form-control" name="base64Pto" style="width: 285px;margin: 0 auto"><br/>
<button class="btn btn-primary" type="submit">
<strong>提交</strong>
</button>
</form>
</div>
</body>
</html>
前端展示页面
<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body class="gray-bg">
<table class="table table-striped table-bordered table-hover dataTables-example">
<thead>
<tr>
<th>序号</th>
<th>出生日期</th>
<th>二进制图片</th>
<th>base64编码图片</th>
</tr>
</thead>
<tbody>
<tr th:each="largeText,stats:${largeTextList}">
<td th:text="${stats.count}"></td>
<td th:text="${largeText.birth}"></td>
<td><img th:src="@{/get_bin_pto(id=${largeText.id})}"></td>
<td><img th:src="@{/get_base64_pto(id=${largeText.id})}"></td>
</tr>
</tbody>
<tfoot>
<tr>
<th>序号</th>
<th>出生日期</th>
<th>二进制图片</th>
<th>base64编码图片</th>
</tr>
</tfoot>
</table>
</body>
</html>
实体类
package priv.happy.hospitaldrugmanagementsystem.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.OutputStream;
import java.io.Serializable;
/**
* @Author: HAPPY
* @Project_name: project
* @Package_name: priv.happy.domain
* @Date: 2021/11/11 10:28
* @Description:
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName(value = "hospital_drug_management_system.large_text")
public class LargeText implements Serializable {
@TableId(value = "id", type = IdType.INPUT)
private Integer id;
@TableField(value = "binary_photo")
private byte[] binaryPhoto;
@TableField(value = "base64_photo")
private String base64Photo;
private static final long serialVersionUID = 1L;
}
controller代码
@Controller
public class LargeTextController {
@Autowired
LargeTextService largeTextService;
/**
* 向数据库中添加大文本数据
* @param largeText 获取基础属性,姓名、出生日期
* @param binPho 以二进制存储的图像
* @param base64Pto 以base64编码存储的图像
* @return 要跳转到的目标请求
*/
@PostMapping("/add_picture_post")
public String savePic(LargeText largeText, @RequestParam("binPto") MultipartFile binPho, @RequestParam("base64Pto") MultipartFile base64Pto) {
// 利用工具类转为二进制编码
largeText.setBinaryPhoto(ImageUtil.getBinary(binPho));
// 利用工具类转为base64编码
largeText.setBase64Photo(ImageUtil.generateBase64(base64Pto));
largeTextService.save(largeText);
return "redirect:view_all_picture_get";
}
/**
* 响应ajax请求,根据编号获取图片的二进制解码流
*
* @param id 图片id
* @return 二进制编码数组
*/
@GetMapping(value = "/get_bin_pto", produces = MediaType.IMAGE_JPEG_VALUE)
@ResponseBody
public byte[] getBinPto(Integer id) {
return largeTextService.getById(id).getBinaryPhoto();
}
/**
* 响应ajax请求,根据编号获取图片的base64解码后的流
*
* @param id 图片id
* @return 二进制编码数组
*/
@GetMapping(value = "/get_base64_pto", produces = MediaType.IMAGE_JPEG_VALUE)
@ResponseBody
public byte[] getBase64Pto(Integer id) {
LargeText largeText = largeTextService.getById(id);
return ImageUtil.decodeBase64Str(largeText.getBase64Photo());
}
// 查询所有数据
@GetMapping("/view_all_picture_get")
public String viewAllPictureGet(Model model) {
List<LargeText> largeTextList = largeTextService.list();
model.addAttribute("largeTextList", largeTextList);
return "largetext/view_all_picture";
}
}
service和mapper都是采用的继承字mybatis-plus的接口直接实现的,没有自己的代码,这里就不写了
工具类
package priv.happy.hospitaldrugmanagementsystem.util;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.Db;
import cn.hutool.db.Entity;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Base64;
import java.util.List;
/**
* @Author: HAPPY
* @Project_name: project
* @Package_name: priv.happy.hospitaldrugmanagementsystem.util
* @Date: 2021/11/14 10:34
* @Description:此工具类用于将文件转为二进制和Base64格式的编码以及解码 base64格式可以起到图像压缩的作用
* 二进制格式不能起到压缩作用
*/
public class ImageUtil {
static BASE64Encoder miscEncoder = new sun.misc.BASE64Encoder();
static BASE64Decoder miscDecoder = new sun.misc.BASE64Decoder();
static Base64.Encoder utilEncoder = Base64.getEncoder();
static Base64.Decoder utilDecoder = Base64.getDecoder();
/**
* 将图片文件编码为base64格式字符串
*
* @param file 图片文件的路径
* @return 返回编码后的字符串
*/
public static String getImageBase64(File file) {
BufferedImage bi;
ByteArrayOutputStream baos = null;
try {
bi = ImageIO.read(file);
baos = new ByteArrayOutputStream();
List<String> split = StrUtil.split(file.getName(), ".");
// 自动截取文件扩展名
String formatName = split.get(split.size() - 1);
ImageIO.write(bi, formatName, baos); // jpg
byte[] bytes = baos.toByteArray();
return miscEncoder.encodeBuffer(bytes).trim();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (baos != null) {
try {
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
/**
* 将base64格式的编码解码为图片文件并在指定路径下生成图片
*
* @param base64String 要解码的字符串
* @param path 生成图片的路径,可以是jpg、png、gif格式
* @return 返回成功与否
*/
public static boolean base64StringToImage(String base64String, String path) {
BufferedImage bi1;
ByteArrayInputStream bais = null;
try {
byte[] bytes1 = miscDecoder.decodeBuffer(base64String);
bais = new ByteArrayInputStream(bytes1);
bi1 = ImageIO.read(bais);
File w2 = new File(path);//
if (!w2.exists()) {
// 如果文件不存在,则创建新文件
w2.createNewFile();
}
ImageIO.write(bi1, "jpg", w2); // 不管输出什么格式图片,此处不需改动
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
} finally {
if (bais != null) {
try {
bais.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 将springboot前端上传的文件编码为base64格式字符串
*
* @param file 上传的文件
* @return 编码后的字符串
*/
public static String generateBase64(MultipartFile file) {
if (file == null || file.isEmpty()) {
return "图片不能为空!";
}
byte[] imageBytes = null;
String base64EncoderImg = "";
try {
imageBytes = file.getBytes();
base64EncoderImg = utilEncoder.encodeToString(imageBytes);
} catch (IOException e) {
e.printStackTrace();
}
return base64EncoderImg;
}
/**
* 将base64字符串解码为二进制流
*
* @param base64String 要解码的字符串
* @return 返回解码后的
*/
public static byte[] decodeBase64Str(String base64String) {
return utilDecoder.decode(base64String);
}
/**
* 将spring boot上传的文件编码为二进制流
* @param file 要编码的文件
* @return 返回文件二进制数组
*/
public static byte[] getBinary(MultipartFile file) {
try {
return file.getBytes();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
数据库
create table hospital_drug_management_system.large_text
(
id int auto_increment
primary key,
binary_photo longblob null,
base64_photo longtext null
);
2.效果图
说明:
- 为了简化起见,本文中我删除了姓名和出生日期
页面
数据库
三、说明
1、 关于工具类
工具类使用了两种Base64的编码和解码方式:
第一种,使用旧版方式
sun.misc.BASE64Decoder;
sun.misc.BASE64Encoder;
第二种,使用新版方式
java.util.Base64;
2、两种编码方式区别:
第一种方式编码和解码处理效率较差,实际测试编码与解码速度,Java 8提供的Base64,要比sun.misc套件提供的快至少11倍!