文章目录

  • 一、前言
  • 1)背景需求
  • 2)重要知识点
  • 二、项目设计
  • 1)整体架构及设计
  • 2)数据库设计
  • 3)服务器 API 设计(前后端交互接口设计)
  • 4)进行源代码的开发
  • 4.1 封装数据库操作
  • 4.2 基于Servlet来搭建服务器
  • 5)前端页面设计
  • 5.1使用HTML模板
  • 5.2基于模板进行删减
  • 5.3使用Vue.js
  • 5.4 实现展示图片
  • 5.5实现展示图片
  • 5.6 完善功能
  • 三、后期加入
  • 1)实现基于白名单方式的防盗链
  • 2)基于 MD5 实现相同内容图片只存一份:类似于百度网盘的 "秒传" 功能


一、前言

1)背景需求

  1. 在我们的日常生活或者工作过程中,有时候我们需要在写博客或者写文档的时候需要插入图片,这个时候我们就需要给定一个链接就把图片的内容获取出来。
  2. 这个服务器可以进行把我们的图片进行上传,下载,查看等等操作,可以适当的作为一个云储存图片的地方。

2)重要知识点

  1. 简单的Web服务器设计的能力
  2. 通过JDBC来操作MySQL数据库
  3. 进行数据库的设计
  4. Gson库的使用,更好的去理解JSON
  5. 强化对HTTP协议的理解
  6. 对Servlet的理解及使用
  7. 基于Md5对图片进行校验
  8. 加深对Postman,Filddler,Tomcat工具的使用
  9. 软件测试的基本理解和方法

二、项目设计

1)整体架构及设计

  • 核心就是一个HTTP服务器,提供对图片的增删改查操作,同时搭配简单的前端页面辅助完成图片的操作展示。

2)数据库设计

数据库的属性:
图片编号:imageId  --> int型非空且自增
图片的名字:imageName   -->  varchar(50)
图片的大小:size  -->   int型
图片的上传时间:uploadTime varchar(50)
图片正文类型:contentType varchar(50)
图片路径:path  varchar(1024)
校验和:md5算法:图片的md5校验和   --> varchar(1024)

java 图片服务器路径 java图片服务器搭建_字符串

  • 数据库存储的是图片的属性(元信息),而图片正文是以文件的形式直接存在磁盘上的,当有一个图片上传到服务器上时,数据库就记录一个path对应到磁盘上的这个文件

    校验和:通过一个更短的字符串,来验证整体数据是否正确。短的字符串是根据原串内容通过一定的规则来计算出来的
    这是一种常见字符串 hash 算法, 具有三个特性:
       1.不管源字符串多长, 得到的最终 md5 值都是固定长度
       2.源字符串稍微变化一点点内容, md5 值会变化很大(降低冲突概率)
       3.通过原字符串很容易计算得到 md5 值, 但是根据 md5 推导出原字符串很难(几乎不可能).

3)服务器 API 设计(前后端交互接口设计)

3.1 Gson的使用
  • 这里我们使用JSON来组织数据。Json 是一种常见是数据格式组织方式. 源于 JavaScript, 是一种键值对风格的数据格式.
  • Java 中可以使用 Gson 库来完成 Json 的解析和构造.

在Maven 中新增 Gson 的依赖

java 图片服务器路径 java图片服务器搭建_java 图片服务器路径_02


一般的时候它会是这个样子:

java 图片服务器路径 java图片服务器搭建_服务器_03

3.2 新增图片

我们先写一个简单的 html 来实现上传图片

java 图片服务器路径 java图片服务器搭建_Vue_04


3.3 查看所有图片元信息

java 图片服务器路径 java图片服务器搭建_Vue_05

3.4 查看指定图片元信息

java 图片服务器路径 java图片服务器搭建_服务器_06

3.5 删除图片

java 图片服务器路径 java图片服务器搭建_服务器_07

3.6 查看图片内容

java 图片服务器路径 java图片服务器搭建_服务器_08

4)进行源代码的开发

4.1 封装数据库操作

4.1.1 创建dao包

(1)先创建DBUtil类实现了封装获取数据库连接的操作

  • 创建一个单例类DBUtail辅助创建连接,其中URL为我的云服务器的MySQL链接

java 图片服务器路径 java图片服务器搭建_java 图片服务器路径_09

  • 这个类主要包含3个方法:

    创建DateSource的实例:DataSource getDataSource()
      获取连接:Connection getConnection()
      关闭连接:void close(Connection connection, PreparedStatement statement, ResultSet resultSet)
          这里关闭的时候要注意:先创建的对象后关闭,后创建的对象先关闭
          close也不是真的销毁连接,只是回收到池子里了,后边还可以用,因为DataSource内置了连接池

(2)创建Image类,每一个image对象对应到一个图片对象(包含图片的相关属性)
(3)创建imageDao类:作为image对象的管理器,借助这个类完成image对象的增删改查操作
(4)使用JDBC的时候是用DataSourse访问数据库的,稍微要比JDBCDriver方式高效一些
(5)当写完一组功能后用单元测试的思想进行测试,也就是将一个类或者方法作为一个单元,然后分开测试,一旦出现了问题,就能及时发现BUG。

4.1.2 了解加回顾
  • 回顾:受查异常与非受查异常

    出现异常之后,处理的具体措施:
    1)当前接触的大部分都是打印调用栈
    2)让程序直接直接终止:及时止损
    3)监控报警通知程序猿
  • 了解jar与war包:类似于zip这样的压缩包,也就是将一大堆.class文件放到一起打包成一个文件

  • 使用maven打包成war包放在服务器上的Tomcat的安装目录里的webapps目录下

4.2 基于Servlet来搭建服务器

Servlet负责处理客户端发来的请求,生成服务器所需要生成的响应

4.2.1  创建api包

(1)在包下创建ImageServlet类继承HttpServlet父类并且重写这个父类中的一些方法,完成图片的增删改查

  • 这个类的 doPost 对应插入图片, doGet 对应查看图片信息, doDelete 对应删除图片.
  • 这里的doGet要分成两种情况, 一个是获取所有图片信息, 一个是获取单个图片信息,根据请求中是否带有 image_id 参数来决定
  • 记得将这个类加到web.xml中,其中的类名要写完整的带包的名字

(2)在包下创建ImageShowServlet类继承HttpServlet父类并且重写这个父类中的doGet方法实现展示图片详细内容

4.2.2 了解加回顾
  • 对Servlet的理解:
    Servlet相关的代码执行方式和平时写的不太一样,平时的代码是从main方法运行的,而Servlet里面没有main方法,而是靠Tomcat来自动调用到Servlet的代码,Tomcat的工作原理和曾经写的Http服务器是很相似的

  • Tomcat的工作步骤:
    (1)启动的时候要绑定端口号(一般是8080)
    (2)进入一个循环
    (3)在主循环里面,调用accept获取到当前的请求的链接
    (4)读取客户端发生的数据(字符串)
    (5)把这个字符串按照Http协议来进行解析
    (6)解析出的Http请求的方法和URL之后,找到对应的Servlet,并执行对应的doXXX方法
    (7)生成响应,回复客户端

  • 理解Tomcat中URL与Servlet的映射关系,步骤如下:
    (1)Tomcat根据URL查找映射关系表(在那个web.xml文件中),找到api.ImageServlet类
    (2)Tomcat根据get方法,决定给你api.ImageServlet类创建一个对象,并且调用其中的doGet方法(这个方法我们一般要进行重写)
    (3)执行doGet方法,往resp对象中写入一些内容
    (4)Tomcat构造resp对象,根据这个对象生成Http响应报文,再通过socket写回给客户端(浏览器或者其他)

5)前端页面设计

5.1使用HTML模板

  • 因为当前的知识对前端不是很了解,所以我们采用对别人的HTML模板就行删减,下载好一个比较好看的模板之后下载到项目的webapp目录中。

    前置知识
  • HTML:网页的骨架 --骨架

  • CSS:描述网页上组件的样式(位置,颜色,大小,字体,背景等等) --皮囊

  • JavaScript:描述前端页面上的一些动作(和用户具体交互的行为) --灵魂

  • HTML,CSS,JavaScript都可以写到同一个HTML文件中,也可以分开写,浏览器加载这个HTML的时候,就会运行到这些代码

5.2基于模板进行删减

(1)导航栏实现上传
  • 文件上传和提交按钮:在原来的input标签下载增加一个input标签,将type改为file,增加name=“filename”,新的input标签type=“submit”

  • 修改form标签属性,新增method(请求方式)=“POST” enctype(上传到服务器上数据的组织类型)=“multipart/form-data” action(访问的路径)="/java_image_server/image"

  • 小问题:发现“上传按钮”和前面不一样高,用style="height:41px"修饰它

(2)页面主题展示图片预览

java 图片服务器路径 java图片服务器搭建_服务器_10

5.3使用Vue.js

前置知识
  • 把网页上显示的预览图片替换成我们服务器上保存的图片:将img标签中src改成服务器存的图片的url就可以了,需要获取服务器上所有的图片的url(ImageServlet),需要通过JS先获取到所有图片的属性,在分别加载每一个图片,使用JS来完成。

  • 此处引入Vue JS的框架来帮助我们更方便的编写代码:JS中变量类型都是在初始化的时候自动推导的。

  • var声明这是一个“变量”,const声明这是一个“常量”。

  • Vue所做的最核心的工作,就是把页面显示的内容和JS中的代码相互关联在一起,修改JS的变量就能很方便的影响到页面的显示情况

  • {{author}}称为“差值表达式”:

    如果是在标签内部使用Vue对象中的数据,就需要使用插值表达式;
     如果是在标签属性中使用Vue对象中的数据就不需要用插值表达式,但是需要搭配Vue的命令
     Vue的命令:v-for:循环访问一个数据
               v-bind:把数据绑定到html标签上的
               v-on:绑定某种事件的处理函数,比如点击鼠标,双击,右键,按下某个键盘,调整窗口大小...

Vue创建对象

java 图片服务器路径 java图片服务器搭建_Vue_11


示例图片:

java 图片服务器路径 java图片服务器搭建_服务器_12

5.4 实现展示图片

修改 html 代码, 和数据关联
  • 使用v-bind:src 把图片的src通过imageShow接口获取到

  • 使用 {{image.imageName}} 表示图片标题

java 图片服务器路径 java图片服务器搭建_服务器_13

从服务器获取数据
  • 在methods中新增获取所有图片的方法

  • ajax: JS中构造HTTP请求发送给服务器的一种实现方式.
  • java 图片服务器路径 java图片服务器搭建_字符串_14

    解决小bug
  • 为了解决浏览器能自动适配图片位置的问题,我们用 $("#app").resize(); 主动触发浏览器 resize 事件即可.

5.5实现展示图片

当前的上传请求会返回一个 JSON 格式的数据. 而我们更需要的是直接能看到上传的效果,解决如下:
  • 修改上传接口的响应, 直接返回一个 302 响应, 重定向回主页.
  • 修改 ImageServlet.doPost 在上传成功代码最后, 加上一个重定向resp.sendRedirect(“index.html”);

5.6 完善功能

图片下方新增删除按钮

java 图片服务器路径 java图片服务器搭建_字符串_15

实现事件处理函数
  • 浏览器给服务器发送一个DELETE /image?imageld= xxx这样的请求就可以了. (ajax完成)

java 图片服务器路径 java图片服务器搭建_java 图片服务器路径_16

解决小bug
  1. 点击删除按钮之后, 会触发预览图片效果:
    这是因为 JavaScript 的事件冒泡机制导致的. 一个标签接受到的事件会依次传给父级标签.
    此处需要阻止 click 事件冒泡. Vue 中使用 v-on:click.stop 即可.
  2. java 图片服务器路径 java图片服务器搭建_java 图片服务器路径_17


  3. java 图片服务器路径 java图片服务器搭建_服务器_18


三、后期加入

1)实现基于白名单方式的防盗链

  1. 当我们不想让别人在别的网站直接使用我们的图片链接时,可以采用如下方法:

  2. 通过 HTTP 中的 refer 字段判定是否是指定网站请求图片.修改 ImageShowServlet.doGet 方法

  3. refer记录了它的上一个请求页面是哪
  4. java 图片服务器路径 java图片服务器搭建_字符串_19

2)基于 MD5 实现相同内容图片只存一份:类似于百度网盘的 “秒传” 功能

(1)前置知识

Md5的特点:

1.不管原串多长,得到的MD5值是固定长度.
2.原串哪怕变动一点点(一个字节), MD5值就会变动很大.
3.计算MD5值的过程很简单,但是通过MD5值无法推测出原字符串的. (应用在密码学)

在我们的项目里Md5的应用:

1.如果两个图片内容完全一样, 就在磁盘上只存-份文件就可以了. 通过MD5就能判定两个图片内容是否是一样的.
2.图片文件虽然是二进制数据,但是本质上也是字符串,针对图片内容计算MD5. 如果两个图片内容相同,得到的MD5 一定是相同的.
3.反之,近似的认为MD5相同,原图片内容一定相同. 理论上是有可能两个图片内容不同,
MD5相同,但是实际,上出现概率极低(MD5自身算法设计.上弓|起的特性)
4.通过Md5计算出的字符串是无法在推算出原文件的,即这是一个不可逆的过程

(2)整体思路

1.修改dao层的代码,在imageDao类里边增加selectByMd5方法,再根据Md5来查找数据库中的图片信息
2.修改上传图片的代码,上传文件时先进行判定,如果这个md5对应的文件存在就不会上传并提示用户该图片已经存在

(3)计算md5

1.在pom.xml中引入依赖

java 图片服务器路径 java图片服务器搭建_java 图片服务器路径_20


2.修改ImageServlet.doPost方法,计算md5

java 图片服务器路径 java图片服务器搭建_java 图片服务器路径_21


3.修改ImageDao类,新增selectByMd5方法

public static Image selectByMd5(String md5) {
        // 1. 获取数据库连接
        Connection connection = DBUtil.getConnection();
        // 2. 构造 SQL 语句
        String sql = "select * from image_table where md5 = ?";
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            // 3. 执行 SQL 语句
            statement = connection.prepareStatement(sql);
            statement.setString(1, md5);
            resultSet = statement.executeQuery();
            // 4. 处理结果集
            if (resultSet.next()) {
                Image image = new Image();
                image.setImageId(resultSet.getInt("imageId"));
                image.setImageName(resultSet.getString("imageName"));
                image.setSize(resultSet.getInt("size"));
                image.setUploadTime(resultSet.getString("uploadTime"));
                image.setContentType(resultSet.getString("contentType"));
                image.setPath(resultSet.getString("path"));
                image.setMd5(resultSet.getString("md5"));
                return image;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 5. 关闭链接
            DBUtil.close(connection, statement, resultSet);
        }
        return null;
    }

4.根据md5决定是否写入文件

  • 修改ImageServlet.doPost方法,如果该md5值的文件存在,则不会存入数据库和磁盘
  • java 图片服务器路径 java图片服务器搭建_java 图片服务器路径_22