一、简单的防盗链
考虑到图片的链接可能会被其他人使用,所以决定通过一定的机制来限制其他人来使用图片(怕使用图片人太多,服务器挂掉)
实现:
1、可以判定当前请求的referer字段(HTTP请求协议中的header 的部分),是不是在代码指定的白名单中,如果是,才允许访问
2、可在代码中用一个hashSet存一下允许的referer就可以了,展示图片的时候判断一下是否存在hashSet中即可
//防盗链机制:白名单
static private HashSet<String> whiteList = new HashSet<>();
static {
whiteList.add("http://127.0.0.1:8080/java_image_server/index.html");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//判断是否在白名单之中
String referer = req.getHeader("Referer");
if (!whiteList.contains(referer)) {
resp.setContentType("application/json; charset: utf-8");
resp.getWriter().write("{ \"ok\": false, \"reason\": \"未授权的访问\" }");
return;
}
二、优化磁盘的存储空间
我发现同一张图片存在硬盘中还是会存两份,所以为了优化磁盘的存储空间,就决定将两份完全一样的图片在磁盘只存一份。
那怎么判断两个图片内容是否一样呢?这就要用到MD5了!
图片文件虽然是二进制数据,但本质上也是字符串,针对图片内容计算MD5。如果两个图片内容相同,得到的MD5一定相同,反之大致也可以。
MD5的特点:
1、不管原串多长,得到的MD5值是固定的长度
2、原串哪怕变动一点,MD5值变动很大
3、计算MD5值的过程很简单,但是通过MD5值无法推测出原字符串的(应用在密码学)
实现思路:
1、上传图片的时候,先判定下新图片的MD5在数据库中是否存在
2、如果已经存在了,就不把图片内容写到磁盘上,如果不存在,才写磁盘
// MD5 计算
image.setMd5(DigestUtils.md5Hex(fileItem.get()));
image.setPath("./image/" + image.getMd5());
// 存到数据库中
ImageDao imageDao = new ImageDao();
// 看看数据库中是否存在相同的 MD5 值的图片, 不存在, 返回 null
Image existImage = imageDao.selectByMd5(image.getMd5());
imageDao.insert(image);
// 2. 获取图片的内容信息, 并且写入磁盘文件
if (existImage == null) {
File file = new File(image.getPath());
try {
fileItem.write(file);
} catch (Exception e) {
e.printStackTrace();
resp.setContentType("application/json; charset=utf-8");
resp.getWriter().write("{ \"ok\": false, \"reason\": \"写磁盘失败\" }");
return;
}
}
但后续发现,如果有多张图片对应同一个磁盘文件,删除任何一个图片,磁盘文件都被删除了,剩余图片无法正常显示
解决办法:通过selectByMD5看看当前MD5值对应的图片在数据库中是否存在,如果不存在,才真正删除磁盘文件!