简易图片服务器项目说明

一. 项目背景

  • 现在很多网页都可以见到上传图片的功能,假如我们上传一张本地图片后,网页就会显示我们刚刚所上传的图片,比如博客上传一张图、个人信息提交头像页面等等。那么这背后的原理是什么呢?
  • 其实当我们浏览网页的时候,本质上是从 对端服务器 获取资源,浏览器在获得这些资源之后进行解析和渲染,呈现在我们用户面前的就是绚丽多彩的页面了。
  • 一般来讲这些资源文档主要有三种格式:HTML、CSS、JS。HTML相当于网页的骨架,CSS相当于网页的衣服,用来规定网页的样式,比如字体大小以及排版等等,而JavaScript则主要负责一些动态的逻辑,比如在网页上按下一个按键后会显示什么等等。

二.项目使用技术栈与环境

所用技术

  • JDBC(Java操作MySQL)
  • 数据库设计(MySQL建库建表,增删查)
  • Gson(反序列化成json字符串)
  • Servlet(服务器端API设计,前后端交互)
  • 基于md5进行校验(决定文件是否要写入磁盘)

平台与环境

  • Windows
  • IDEA
  • Maven

三.项目功能

  • 核心就是实现一个 HTTP 服务器,实现对图片的增删查功能,同时搭配简单的页面辅助完成对图片的上传,显示,阅览功能。(实现一个 HTTP 服务器,然后用这个服务器来存储图片,针对每个图片提供一个唯一的 url,有了这个 url 之后就可以借助它把图片展示到其他网页上。)
  • 本项目的结构主要分为两个部分,数据存储模块和服务器模块。使用MySQL存储图片的属性信息,将图片内容保存到本地磁盘,服务器向外提供诸如上传图片、获取单个图片的属性信息、获取所有图片的属性信息、和删除图片等API接口。

四.项目具体实现

4.1:数据库、表的设计

在这里插入图片描述
(1)imageId:图片的 id ,设置为自增主键
(2)imageName:图片名称
(3)size:图片大小
(4)uploadTime:图片的上传时间
(5)contentType:图片的类型(image/jpg,image/png等)
(6)path:图片在磁盘上的存储路径
(7)md5:一种计算校验和的算法(主要用来判断两张图片是否内容相同,即是否两张图片一样)

知识扫盲:什么是md5

这是一种常见的字符串 hash 算法, 具有三个特性:

  • 不管源字符串多长, 得到的最终 md5 值都是固定长度
  • 源字符串稍微变化一点点内容, md5 值就会变化很大(降低冲突概率)
  • 通过原字符串很容易计算得到 md5 值,但是根据 md5 推导出原字符串很难(几乎不可能)
  • md5 常用于哈希算法,加密算法,校验和

4.2:pom.xml文件中引入依赖

:JSON 是一种常见的数据格式组织方式,源于 JavaScript , 是一种键值对风格的数据格式。Java 中可以使用 Gson 库来完成 JSON 的解析和构造. 在 Maven 中新增 对 Gson 库的依赖就可以使用 JSON 了

<!-- 打包方式是 war 包,一种用于 web 应用的包,原理类似 jar 包 -->
    <packaging>war</packaging>

    <!-- 指定属性信息 -->
    <properties>
        <encoding>UTF-8</encoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <!-- 加入 servlet 依赖 -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <!-- servlet 版本和 tomcat 版本有对应关系,切记 -->
            <version>3.1.0</version>
            <!-- 这个意思是我们只在开发阶段需要这个依赖,部署到 tomcat 上时就不需要了 -->
            <scope>provided</scope>
        </dependency>
        <!--单元测试矿浆junit依赖 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.49</version>
        </dependency>
        <!--JSON库,gson-->
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.2</version>
        </dependency>
        <!--对应上传图片操作 -->
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.4</version>
        </dependency>
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.14</version>
        </dependency>
    </dependencies>

    <build>
        <!-- 指定最终 war 包的名称 -->
        <finalName>image_server</finalName>

4.3:服务器端封装数据库的的设计

4.3.1:前期准备工作,首先创建一个maven项目

(1)Maven 是什么?

Maven是 Apache 下的一个纯 Java 开发的开源项目,是一个项目构建和管理的工具;它提供了帮助管理、 构建、文档、报告、依赖、发布、分发的方法。可以方便的编译代码、进行依赖管理、管理二进制库等等。Maven是专门用于构建和管理Java相关项目的工具

(2)使用 Maven 的好处?

maven 的目标是完成项目构建解决一切繁琐事宜。我们具体关注它的以下功能:

  • 提供一个标准的项目工程目录
  • 提供项目描述
  • 提供强大的版本管理工具
  • 可以分阶段的进行构建过程
  • 提供了丰富的插件库使用

4.3.2:dao 包下封装对数据库的相关操作
在这里插入图片描述
具体代码实现:
DBUtil工具类:

/**
 * 创建一个单例类来辅助创建连接,关闭连接
 */
public class DBUtil {
    private static volatile DataSource dataSource = null;//管理数据源

    // 通过这个方法来创建 DataSource 的实例
    public static DataSource getDataSource() {
        //单例模式(双重校验+锁+volatile的饿汉模式)
        //加锁实际上会牺牲效率,所以不要每次都加锁,只要判断datasource不为空,就直接返回dataSource对象,保证效率
        if (dataSource == null) {
            synchronized (DBUtil.class) {
                if (dataSource == null) {
                    dataSource = new MysqlDataSource();
                    MysqlDataSource tmpDataSource = (MysqlDataSource) dataSource;
                    tmpDataSource.setURL("jdbc:mysql://localhost:3306/image_server_project?user=root&password=1450618603&useSSL=false&characterEncoding=UTF-8");
                }
            }
        }
        return dataSource;
    }

    //建立数据库连接方法
    public static Connection getConnection() {
        try {
            return getDataSource().getConnection();
        } catch (SQLException e) {
           throw new RuntimeException("数据库连接失败");
        }
    }

    //关闭数据库连接方法
    public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet) {
        try {
            if (resultSet != null) {
                resultSet.close();
            }
            if (statement != null) {
                statement.close();
            }
            if (connection != null) {
                connection.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

Image图片类:

/**
 *  一个 Image 对象:和数据库表的设计相对应
 */
public class Image {
    private int imageId;
    private String imageName;
    private int size;
    private String uploadTime;    //图片上传时间
    private String contentType;   //图片的格式:image.jpg/image.png 等等
    private String path;           //图片应该往磁盘写的位置
    private String md5;            //校验和机制(用于判断两张图片的内容是否相同)

    public int getImageId() {
        return imageId;
    }

    public void setImageId(int imageId) {
        this.imageId = imageId;
    }

    public String getImageName() {
        return imageName;
    }

    public void setImageName(String imageName) {
        this.imageName = imageName;
    }

    public int getSize() {
        return size;
    }

    public void setSize(int size) {
        this.size = size;
    }

    public String getUploadTime() {
        return uploadTime;
    }

    public void setUploadTime(String uploadTime) {
        this.uploadTime = uploadTime;
    }

    public String getContentType() {
        return contentType;
    }

    public void setContentType(String contentType) {
        this.contentType = contentType;
    }

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    public String getMd5() {
        return md5;
    }

    public void setMd5(String md5) {
        this.md5 = md5;
    }

    @Override
    public String toString() {
        return "Image{" +
                "imageId=" + imageId +
                ", imageName='" + imageName + '\'' +
                ", size=" + size +
                ", uploadTime='" + uploadTime + '\'' +
                ", contentType='" + contentType + '\'' +
                ", path='" + path + '\'' +
                ", md5='" + md5 + '\'' +
                '}';
    }
}

数据库操作类:


/**
 *  用来对数据库的增删改查的一个类
 *  JDBC的操作流程
 *     1.获取数据库连接
 *     2.创建并拼装SQL语句
 *     3.执行SQL语句
 *     4.关闭结果集resultSet对象、关闭statement对象,关闭连接
 */


public class ImageDao {

    /**
     * 把一个 Image 对象插入到数据库中
     */
    public boolean insert(Image image){
        Connection connection = null;
        PreparedStatement statement = null;
        try {
            //1.获取数据库连接
            connection = DBUtil.getConnection();

            //2.创建并拼接sql语句
            String sql = "insert into image_table values(null,?,?,?,?,?,?)";
            statement = connection.prepareStatement(sql);
            statement.setString(1,image.getImageName());
            statement.setInt(2,image.getSize());
            statement.setString(3,image.getUploadTime());
            statement.setString(4,image.getContentType());
            statement.setString(5,image.getPath());
            statement.setString(6,image.getMd5());

            //3.执行sql语句
            int ret = statement.executeUpdate();
            if (ret!=1) {
                throw new RuntimeException("插入数据库出错");
            }else {
                return true;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //4.关闭资源
            DBUtil.close(connection,statement,null);
        }
        return false;
    }


    /**
     *  查找数据库中所有图片的属性信息,并存储在 List 列表中
     * @return 所有图片信息
     */
    public List<Image> selectAll(){
        List<Image> images = new ArrayList<>();
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet= null;
        try {
            connection = DBUtil.getConnection();
            String sql = "select * from image_table";
            statement = connection.prepareStatement(sql);
            resultSet = statement.executeQuery();
            while (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"));

                images.add(image);
            }
            return images;
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //关闭结果集,statement对象和连接
            DBUtil.close(connection,statement,resultSet);
        }
        return null;//出错的话返回空的结果集
    }


    /**
     * 根据 imageId 查找指定图片的属性信息
     * @param imageId
     * @return 返回根据id查找到的图片信息
     */
    public Image selectById(int imageId){
        Connection  connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            connection = DBUtil.getConnection();
            String sql = "select * from image_table where imageId = ?";
            statement = connection.prepareStatement(sql);
            statement.setInt(1,imageId);

            resultSet = statement.executeQuery();
            while (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.关闭连接和statement对象
           DBUtil.close(connection,statement,resultSet);
        }
        return null;  //如果失败的话返回null
    }


    /**
     * 根据 imageId 删除指定图片
     * @param imageId
     */
    public void delete(int imageId){
        Connection connection = null;
        String sql = "delete  from image_table where imageId = ?";
        PreparedStatement statement = null;
        try {
            connection = DBUtil.getConnection();
            statement = connection.prepareStatement(sql);
            statement.setInt(1,imageId);
            int ret = statement.executeUpdate();
            if (ret != 1) {
                throw  new RuntimeException("删除数据库异常");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            DBUtil.close(connection,statement,null);
        }
    }

    //根据MD5的值在数据库中查找数据
    public Image selectByMD5(String md5) {
        Connection  connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            connection = DBUtil.getConnection();
            String sql = "select * from image_table where md5 = ?";
            statement = connection.prepareStatement(sql);
            statement.setString(1,md5);

            resultSet = statement.executeQuery();
            while (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.关闭连接和statement对象
            DBUtil.close(connection,statement,resultSet);
        }
        return null;  //如果失败的话返回null
    }
}

4.4:服务器端servlet接口的设计

在这里插入图片描述

首先创建一个 api 包,在这个包中创建两个 Servlet 类,这两个Servlet 类都继承自 HttpServlet类,然后重写了对应的 doxxx() 方法。
一个用来完成图片的增删查操作(ImageServlet类)
一个用来展示图片的详细内容(ImageShowServlet类)
注意:要把这两个Servlet 类都要配置到 web.xml 文件中,其中类名要写完整的带包名的名字

    <servlet>
        <servlet-name>ImageServlet</servlet-name>
        <servlet-class>api.ImageServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>ImageServlet</servlet-name>
        <url-pattern>/image</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>ImageShowServlet</servlet-name>
        <servlet-class>api.ImageShowServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>ImageShowServlet</servlet-name>
        <url-pattern>/imageShow</url-pattern>
    </servlet-mapping>

imageServlet类:

public class ImageServlet extends HttpServlet {


    /**
     * 查询所有图片/指定图片的内容
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //通过URL中是否带有imageId参数来区分是查看所有图片还是指定图片
        //例如:URL为  /image/imageId=100 name则是查看imageId为100的图片信息
        //     如果URL后面的键值对都不存在或者只存在键无值,就查询所有图片信息
        String imageId = request.getParameter("imageId");
        if (imageId == null || imageId.equals("")) {
            //查看所有图片信息
            selectAll(request,response);
        }else {
            //查看指定图片信息
            selectById(imageId,response);
        }
    }

    /**
     *  查看指定图片信息
     * @param imageId
     * @param response
     */
    private void selectById(String imageId, HttpServletResponse response) throws IOException {
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/json");

        //1.创建一个ImageDao对象,根据指定id在数据库中查找
        ImageDao imageDao = new ImageDao();
        Image image = imageDao.selectById(Integer.parseInt(imageId));

        //2.创建Gson对象,将查到的数据转换成JSON字符串格式,并且写给响应response对象
        Gson gson = new GsonBuilder().create();
        String jsonData = gson.toJson(image);

        //发送响应给前端
        PrintWriter writer = response.getWriter();
        writer.println(jsonData);
    }

    private void selectAll(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/json");

        ImageDao imageDao = new ImageDao();
        List<Image> images = imageDao.selectAll();
        Gson gson = new GsonBuilder().create();
        String jsonData = gson.toJson(images);
        PrintWriter writer = response.getWriter();
        writer.println(jsonData);
    }

    /**
     *  上传图片
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {


        //1.获取图片信息,并存入数据库
        //  1.1需要创建一个factory对象和upload对象,为了获取到图片属性做的准备工作
        FileItemFactory factory = new DiskFileItemFactory();
        ServletFileUpload upload = new ServletFileUpload(factory);
        //  1.2通过upload对象进一步解析请求(解析HTTP请求中的 body 部分)
        //  理论上来说,HTTP 支持一个请求中同时上传多个文件,FileItem 就代表上传的一个文件对象,多个文件用 List 组织
        List<FileItem> items = null;
        try {
             items = upload.parseRequest(request);
        } catch (FileUploadException e) {
            //出现异常说明解析出错
            e.printStackTrace();
            //告诉客户端出现的具体错误信息
            PrintWriter writer = response.getWriter();
            response.setCharacterEncoding("utf-8");
            response.setContentType("application/json");
            writer.write("{\"ok\":false \"reason\":\"上传图片请求解析失败\"}");
            return;
        }
        //   1.3将FileItem中的对象提取出来转换成Image对象,才能存到数据库中
        FileItem fileItem = items.get(0);
        Image image = new Image();
        image.setImageName(fileItem.getName());
        image.setSize((int)fileItem.getSize());
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = new Date();
        String time = simpleDateFormat.format(date);
        image.setUploadTime(time);
        image.setContentType(fileItem.getContentType());
        //计算md5的值
        image.setMd5(DigestUtils.md5Hex(fileItem.get()));// md5 值是十六进制的字符串 图片内容相同时则md5值相同,图片内容不同时,md5值不同
        //自定义存储路径,加上数据保证不会出现连续插入两张图片报错,因为每时每刻时间戳是唯一的
        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();
                //出现异常说明写入文件失败
                PrintWriter writer = response.getWriter();
                response.setCharacterEncoding("utf-8");
                response.setContentType("application/json");
                writer.write("{\"ok\":false \"reason\":\"图片内容写入磁盘失败\"}");
                return;
            }
        }


       /* PrintWriter writer = response.getWriter();
        writer.write("{\"ok\":true}");*/
        response.sendRedirect("index.html");
    }

    /**
     *  删除指定图片
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */

    @Override
    protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //1.先获取请求中的imageId
        String imageId = req.getParameter("imageId");
        if (imageId==null || imageId.equals("")) {
            resp.setStatus(200);
            resp.setCharacterEncoding("utf-8");
            resp.setContentType("application/json");
            PrintWriter writer = resp.getWriter();
            writer.write("{\"ok\":\"false\" \"reason\":\"解析请求失败\"}");
            return;
        }

        //2.创建ImageDao对象,查看到该图片对象对应的相关属性,若存在则要删除
        //  既要删除数据库中的内容,也要删除磁盘中存储的对应图片,因此要知道该 imageId 对应的图片对象的存储路径
        ImageDao imageDao = new ImageDao();
        Image image = imageDao.selectById(Integer.parseInt(imageId));
        if (image == null) {
            //说明请求中传入的id在数据库中不存在
            resp.setStatus(200);
            resp.setCharacterEncoding("utf-8");
            resp.setContentType("application/json");
            PrintWriter writer = resp.getWriter();
            writer.write("{\"ok\":\"false\" \"reason\":\"数据库中不存在该数据\"}");
            return;
        }

        //3.删除数据库中的记录
        imageDao.delete(Integer.parseInt(imageId));

        // 4.删除本地磁盘文件(注意:数据库中可能有多张相同的图片,但是磁盘中只写入了一张图片,删除要注意)
        //   刚刚已经从数据库中删除了那张图片,若此时数据库中还存有相同的图片,那么不应该删除磁盘图片文件
        //   相同图片的 md5 值是相同的
        Image existImage = imageDao.selectByMD5(image.getMd5());
        // 如果删除完毕后,数据库中没有相同的图片了,那么就删除磁盘文件,否则就不删除
        if (existImage == null) {
            File file = new File(image.getPath());
            file.delete();
            resp.setStatus(200);
        }
    }
}

imageShowServlet类:


public class ImageShowServlet extends HttpServlet {
    //基于白名单的防盗链机制
    static private HashSet<String> whiteList = new HashSet<>();
    //白名单
    static {
        whiteList.add("http://localhost:8080/index.html");
        whiteList.add("http://localhost:8080/image_server/index.html");
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //防盗链功能,因为服务器同时访问人太多容易崩溃
        String referer = request.getHeader("Referer");
        if (!whiteList.contains(referer)) {
            response.setContentType("application/json; charset=utf-8");
            response.getWriter().write("{ \"ok\":false,\"reason\":\"该网站未授权访问\" }");
            return;
        }

        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/json");

        //1.解析出imageId
        String imageId = request.getParameter("imageId");
        if (imageId==null || imageId.equals("")) {
            PrintWriter writer = response.getWriter();
            writer.write("{\"ok\":\"false\" \"reason\":\"数据解析失败\"}");
            return;
        }
        //2.根据imageId查找数据库,得到对应的图片属性信息(需要知道图片存储的路径)
        ImageDao imageDao = new ImageDao();
        Image image = imageDao.selectById(Integer.parseInt(imageId));
        //3.根据路径打开文件,读取其中的内容,写入到响应体中
        response.setContentType(image.getContentType());
        File file = new File(image.getPath());

        //由于图片是二进制文件,因此使用字节流方式读取
        FileInputStream fileInputStream = new FileInputStream(file);
        ServletOutputStream outputStream = response.getOutputStream();
        byte[] buffer = new byte[1024];
        while (true) {
            int len = fileInputStream.read(buffer);
            if (len == -1) {
                //文件读取完毕
                break;
            }
            //此时已经读到一部分数据,在buffer中存着,应该写到响应对象中
            outputStream.write(buffer);
        }
        fileInputStream.close();
        outputStream.close();
    }

}

至此,后端代码告一段落

4.5:前端代码实现:

有句话说的好,下坡易上坡难,我们不会做加法,就学着去做减法,前端不太
了解的情况我们可以在网上下载一些前端模板,对其删减已达到我们想要的效果

基于模板进行删减修改:
(1)title 标签的修改
在这里插入图片描述
(2)页面的选择文件和提交按钮
在这里插入图片描述
注意:为了让 “提交按钮” 和前面的选择文件一样高, 这里加了一个style=“height:41px”
此处我们直接使用 style 属性调整样式, 这是一个简单粗暴的做法. 事实上专业的前端开发很少这样做, 因为代码的可维护性不好

(3)页面 Logo 的修改

在这里插入图片描述
在这里插入图片描述

(4)使用 Vue

Vue 是 JS 的框架,他做的核心工作是把页面显示的内容和 JS 中的代码相互关联到一起,修改 JS 中的变量就能很方便的影响到页面的显示情况。
在这里插入图片描述

Vue的基本用法:
在这里插入图片描述
var 声明这是一个变量,构造方法是使用了 JSON 形式的{} ,el 属性表示我要把当前这个对象关联上某一个 html 的标签(把 app 对象关联到 html 中一个 id=“app” 的标签)

主要JS代码:

第一步: id=“app” 把 JS 代码和 该标签绑定
第二步:使用 v-bind:src 把图片的内容 通过 ImageShowServlet 接口获取到.
第三步:使用 {{image.imageName}} 表示图片的名称
第四步:v-for 能够循环访问一个数据
注:只要访问 index.html 文件就要加载服务器中的所有图片,所以只要访问 index.html 文件,就要调用该方法


<script>
    var app=new Vue({
        // e1 属性表示我要把当前这个对象关联到某一个 html 的标签上(把 app 对象关联到 html 中的一个 id="app 的标签)
        el: '#app',
        data: {
            images: [    //一个集合数组
            ]
        },
        methods:{
            // 请求格式:   GET /image
            getImages(){
                $.ajax({   // ajax 是在JS中构造 http 请求发送给服务器的一种实现方式
                    url:"image",
                    type:"get",
                    context:this,
                    success:function (data,status) {
                        //此处的代码在浏览器收到响应之后,才会执行到
                        //参数中的 data 就相当于收到的 http 响应中的 body 部分
                        this.images=data;
                        $('#app').resize();   //触发浏览器,让它自动调整大小,让图片正确显示
                    }
                })
            },
            // 请求格式:   DELETE /image?imageId=
            remove(imageId){
                $.ajax({
                    url:"image?imageId="+imageId,
                    type:"delete",
                    context:this,
                    success:function (data,status) {
                        this.getImages(); //只要删除图片,就重新获取一下服务器上剩余的图片,保证页面显示的图片数量正常
                        alert("删除图片成功!");//弹出一个对话框
                    }
                })
            }
        }
    })
    app.getImages();         //项目只要访问 index.html 就自动调用该方法
</script>

(5)在返回完后端代码完善上传功能

当前的上传请求成功后会返回一个 JSON 格式的数据. 而我们需要的是直接能看到上传的效果,因此应该修改响应,直接重定向到 index.html 页面观察即可。
修改上传接口中的响应, 直接返回一个 302 响应, 重定向回主页即可。
在这里插入图片描述
(6)实现删除图片
在这里插入图片描述
此程序的事件冒泡机制:div 标签中有 3 个字标签
①点击 div 就会触发一个点击事件,div 就会处理这个点击事件并显示预览图
②点击 button 删除按钮的时候也会触发一个点击事件,触发删除操作
③点击 cilck 就会先被 button 处理,进行删除操作,然后顺着 button 的父标签,传递给 div 标签,然后 div 再处理一次,触发预览图效果

4.6:项目的两个拓展点:

4.6.1:防盗链机制:增加安全性
通过 HTTP 请求中的 Refer 字段判定是否是指定网站请求服务器图片,未授权网站就无法访问图片内容。

4.6.2:md5校验和机制:实现相同内容的图片在磁盘上只能存一份
整体思路:

  • 修改 dao 层代码,在 dao 层实现一个selectByMd5()的方法,根据 Md5 值来查找数据库中的图片信息(是否存在多张相同图片).
  • 修改上传图片代码,在磁盘上存储文件时先判定,该 md5 对应的图片是否已经存在于磁盘上了,若存在就不必再往磁盘写了.
  • 修改删除图片代码,先删除数据库记录,删除完毕后,看数据库中是否还存在刚刚相同的 md5 的记录.如果不存在,就删除磁盘文件.

五:项目效果展示

效果图:在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
此处我们发现,数据库和浏览器都存有7张图片,然而本地磁盘只存有六张图片,这正是由于我们用了md5实现了相同内容的图片在磁盘上只能存一份,并加入了时间戳,保证每时每刻的时间是不相同的,所以即使两张图片的内容相同,但是由于时间是不同的,所以图片数据插入数据库不会报错,至此整个项目基本就告一段落了,由于本人能力有限,些许地方还有实现不当,希望各位小伙伴发现了可以不吝批评

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值