【图片服务器】实现思想代码+具体测试

一、项目概述

1、效果展示

这个项目做的是实现一个类似于相册的功能,可以进行图片的上传、查看、删除功能;那它有哪些应用场景呢?最常见的比如在写csdn时,想插入一张图片,让你输入图片链接地址时,这时就可以把图片的url拿过来;

2、核心技术

①、第三方库的使用,比如fileupload、Servlet、gson等
②、JavaEE,JAVA和数据库还有tomcat的综合应用
③、基于MD5进行校验
⑤、HTTP协议的应用
⑥、简单的前端实现HTML+CSS+JS
⑦、GSON数据格式
⑧、软件测试的基本思想应用
⑨、maven的使用
为什么选择maven开发?

1、maven一个命令就可以完成项目构建过程
2、他可以进行强大的依赖管理
3、可以分阶段进行构建
4、提供web项目的模式

3、设计思想

实现一个HTTP服务器对图片进行增删查,分步讨论,
查:用户有两种需求,想查看所有的图片,那直接输入访问,如果想查看指定的某一张就需要提供图片的具体ID
增和删:一张图片的保存分为属性和图片具体内容,属性存在数据库里,图片的具体内容存在磁盘文件当中
一张图片的属性应该有哪些?id不用说,接下来肯定要有名称、图片尺寸、上传时间、图片的类型、图片的路径、MD5是为了去重引入的一个字段,下面会介绍
在这里插入图片描述
md5:计算校验和,在应用层对数据进行校验,把长字符串通过一定规则变成短字符串,来判断两张图片是否是一张图片

二、项目的具体实现

1、建立数据库连接

把它封装到一个类里,用的是单例模式,这个类只能创建一个实例,节省资源,但会出现线程不安全,解决办法是三步走(加锁、volatile、双重判断),最后记得关闭数据库连接,

public class DBUtil {
    private static final String URL = "jdbc:mysql://127.0.0.1:3306/java_image_server?characterEncoding=utf8&useSSL=true";
    private static final String USERNAME = "root";
    private static final String PASSWORD = "123456";

    private static volatile DataSource dataSource = null;

    public static DataSource getDataSource() {
        // 通过这个方法来创建 DataSource 的实例
        if (dataSource == null) {
            synchronized (DBUtil.class) {
                if (dataSource == null) {
                    dataSource = new MysqlDataSource();
                    MysqlDataSource tmpDataSource = (MysqlDataSource) dataSource;
                    tmpDataSource.setURL(URL);
                    tmpDataSource.setUser(USERNAME);
                    tmpDataSource.setPassword(PASSWORD);
                }
            }
        }
        return dataSource;
    }

    public static Connection getConnection() {
        try {
            return getDataSource().getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    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();
        }
    }
}

2、创建一个类放图片的属性

public class Image {
    private int imageId;
    private String imageName;
    private int size;
    private String uploadTime;
    private String contentType;
    private String path;
    private String md5;//Image类把属性设置成私有,对外不可见,所以要有get(取值) set(赋值)方法

    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 + '\'' +
                '}';
    }
}

3、数据库的增删查

简单分为4步
①获取数据库连接
②创建并拼装SQL语句
③执行sql语句
④关闭数据库连接

public class ImageDao {
    /**
     * 把 image 对象插入到数据库中
     * @param image
     */
    public void insert(Image image) {
        // 1. 获取数据库连接
        Connection connection = DBUtil.getConnection();
        // 2. 创建并拼装 SQL 语句
        String sql = "insert into image_table values(null, ?, ?, ?, ?, ?, ?)";
        PreparedStatement statement = null;//存放数据库里取出的结果集对象
        try {
            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) {  //不等于1说明没插进来
                // 程序出现问题, 抛出一个异常
                throw new JavaImageServerException("插入数据库出错!");
            }
        } catch (SQLException | JavaImageServerException e) {
            e.printStackTrace(); //解决异常方法是打印栈
        } finally {
            // 4. 关闭连接和statement对象
            DBUtil.close(connection, statement, null);
        }
    }

    /**
     * 查找数据库中的所有图片的信息
     * @return
     */
    public List<Image> selectAll() {
        List<Image> images = new ArrayList<>();
        // 1. 获取数据库连接
        Connection connection = DBUtil.getConnection();
        // 2. 构造 SQL 语句
        String sql = "select * from image_table";
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            // 3. 执行 SQL 语句
            statement = connection.prepareStatement(sql);
            resultSet = statement.executeQuery();//把数据库响应的查询结果放在result对象中供使用
            // 4. 处理结果集
            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 {
            // 5. 关闭连接
            DBUtil.close(connection, statement, resultSet);
        }
        return null;
    }

    /**
     * 根据 imageId 查找指定的图片信息
     * @param imageId
     * @return
     */
    public Image selectOne(int imageId) {
        // 1. 获取数据库连接
        Connection connection = DBUtil.getConnection();
        // 2. 构造 SQL 语句
        String sql = "select * from image_table where imageId = ?";
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            // 3. 执行 SQL 语句
            statement = connection.prepareStatement(sql);
            statement.setInt(1, imageId);
            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;
    }

    /**
     * 根据 imageId 删除指定的图片
     * @param imageId
     */
    public boolean delete(int imageId) {
        // 1. 获取数据库连接
        Connection connection = DBUtil.getConnection();
        // 2. 拼装 SQL 语句
        String sql = "delete from image_table where imageId = ?";
        PreparedStatement statement = null;
        // 3. 执行 SQL 语句
        try {
            statement = connection.prepareStatement(sql);
            statement.setInt(1, imageId);
            int ret = statement.executeUpdate();
            if (ret != 1) {
                throw new JavaImageServerException("删除数据库操作失败");
            }
        } catch (SQLException | JavaImageServerException e) {
            e.printStackTrace();
        } finally {
            // 4. 关闭连接
            DBUtil.close(connection, statement, null);
        }
        return false;
    }

    public static void main(String[] args) {
        //4. 测试删除图片
        //ImageDao imageDao = new ImageDao();
        //imageDao.delete(1);
    }

    public 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、实现servlet服务

继承HttpServlet覆写里面的doget、dopost、dodelete方法来实现
post方法
获取到图片相关的元信息(Image对象), 并写入数据库
1、创建 factory 对象和 upload 对象
2、使用 upload 对象解析请求
3、对请求信息进行解析, 转换成 Image 对象
4、将 Image 对象写入数据库中
5、获取到图片内容, 写入到磁盘中
这里也引入servlet第三方库

 <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>在这里插入代码片
public class ImageServlet extends HttpServlet {
    /**
     * 查看图片属性: 既能查看所有, 也能查看指定
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 考虑到查看所有图片属性和查看指定图片属性
        // 通过是否 URL 中带有 imageId 参数来进行区分.
        // 存在 imageId 查看指定图片属性, 否则就查看所有图片属性
        // 例如: URL /image?imageId=100
        // imageId 的值就是 "100"
        // 如果 URL 中不存在 imageId 那么返回 null
        String imageId = req.getParameter("imageId");//获得客户端设置的数据
        if (imageId == null || imageId.equals("")) {
            // 查看所有图片属性
            selectAll(req, resp);
        } else {
            // 查看指定图片
            selectOne(imageId, resp);
        }
    }

    private void selectAll(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        resp.setContentType("application/json; charset=utf-8");//设置发送到客户端的响应内容类型
        // 1. 创建一个 ImageDao 对象, 并查找数据库
        ImageDao imageDao = new ImageDao();
        List<Image> images = imageDao.selectAll();
        // 2. 把查找到的结果转成 JSON 格式的字符串, 并且写回给 resp 对象
        Gson gson = new GsonBuilder().create();
        //    jsonData 就是一个 json 格式的字符串了, 就和之前约定的格式是一样的了.
        //    重点体会下面这行代码, 这个方法的核心, gson 帮我们自动完成了大量的格式转换工作
        //    只要把之前的相关的字段都约定成统一的命名, 下面的操作就可以一步到位的完成整个转换
        String jsonData = gson.toJson(images);
        resp.getWriter().write(jsonData);//发送请求内容至页面,直接在页面输出内容
    }

    private void selectOne(String imageId, HttpServletResponse resp) throws IOException {
        resp.setContentType("application/json; charset=utf-8");
        // 1. 创建 ImageDao 对象
        ImageDao imageDao = new ImageDao();
        Image image = imageDao.selectOne(Integer.parseInt(imageId));
        // 2. 使用 gson 把查到的数据转成 json 格式, 并写回给响应对象
        Gson gson = new GsonBuilder().create();
        String jsonData = gson.toJson(image);
        resp.getWriter().write(jsonData);
    }

    /**
     * 上传图片
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 1. 获取图片的属性信息, 并且存入数据库
        //  a) 需要创建一个 factory 对象 和 upload 对象, 这是为了获取到图片属性做的准备工作
        //     固定的逻辑
        FileItemFactory factory = new DiskFileItemFactory();//实现文件上传
        ServletFileUpload upload = new ServletFileUpload(factory);
        // b) 通过 upload 对象进一步解析请求(解析HTTP请求中奇怪的 body 中的内容)
        //    FileItem 就代表一个上传的文件对象.
        //    理论上来说, HTTP 支持一个请求中同时上传多个文件
        List<FileItem> items = null;
        try {
            items = upload.parseRequest(req);
        } catch (FileUploadException e) {
            // 出现异常说明解析出错!
            e.printStackTrace();
            // 告诉客户端出现的具体的错误是啥
            resp.setContentType("application/json; charset=utf-8");
            resp.getWriter().write("{ \"ok\": false, \"reason\": \"jiexi failed\" }");
            return;
        }
        //  c) 把 FileItem 中的属性提取出来, 转换成 Image 对象, 才能存到数据库中
        //     当前只考虑一张图片的情况
        FileItem fileItem = items.get(0);//FileItem类是一个接口,它的实现类是DiskFileItem
        Image image = new Image();
        image.setImageName(fileItem.getName());
        image.setSize((int)fileItem.getSize());
        // 手动获取一下当前日期, 并转成格式化日期, yyMMdd => 20200218
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");//选择用户定义的时期
        image.setUploadTime(simpleDateFormat.format(new Date()));
        image.setContentType(fileItem.getContentType());
        // 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\": \"Write disk failed\" }");
                return;
            }
        }

        // 3. 给客户端返回一个结果数据
        //resp.setContentType("application/json; charset=utf-8");
       // resp.getWriter().write("{ \"ok\": true }");
        resp.sendRedirect("index.html");
        //http://192.168.3.24:8080/java_image_server/index.html
    }

    /**
     * 删除指定图片
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("application/json; charset=utf-8");
        // 1. 先获取到请求中的 imageId
        String imageId = req.getParameter("imageId");//获取客户端请求的数据
        if (imageId == null || imageId.equals("")) {
            resp.setStatus(200);
            resp.getWriter().write("{ \"ok\": false, \"reason\": \"jiexi failed\" }");
            return;
        }
        // 2. 创建 ImageDao 对象, 查看到该图片对象对应的相关属性(这是为了知道这个图片对应的文件路径)
        ImageDao imageDao = new ImageDao();
        Image image = imageDao.selectOne(Integer.parseInt(imageId));
        if (image == null) {
            // 此时请求中传入的 id 在数据库中不存在.
            resp.setStatus(200);
            resp.getWriter().write("{ \"ok\": false, \"reason\": \"imageId not exist in db\" }");
            return;
        }
        // 3. 删除数据库中的记录
        imageDao.delete(Integer.parseInt(imageId));
        // 4. 删除本地磁盘文件
        File file = new File(image.getPath());
        file.delete();
        resp.setStatus(200);
        resp.getWriter().write("{ \"ok\": true }");
    }

5、让图片展示的Servlet

1、先要解析出Imageid
2、根据ID去数据库中查找。得到图片的属性
3、根据路径打开文件,以流的形式读取内容
4、把读到的数据写到响应对象中

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 1. 解析出 imageId
        String imageId = req.getParameter("imageId");
        if (imageId == null || imageId.equals("")) {
            resp.setContentType("application/json; charset: utf-8");
            resp.getWriter().write("{ \"ok\": false, \"reason\": \"imageId Resolution failure\" }");
            return;
        }
        // 2. 根据 imageId 查找数据库, 得到对应的图片属性信息(需要知道图片存储的路径)
        ImageDao imageDao = new ImageDao();
        Image image = imageDao.selectOne(Integer.parseInt(imageId));
        // 3. 根据路径打开文件, 读取其中的内容, 写入到响应对象中
        resp.setContentType(image.getContentType());
        File file = new File(image.getPath());
        // 由于图片是二进制文件, 应该使用字节流的方式读取文件
        OutputStream outputStream = resp.getOutputStream();
        FileInputStream fileInputStream = new FileInputStream(file);
        byte[] buffer = new byte[1024];
        while (true) {
            int len = fileInputStream.read(buffer);
            if (len == -1) {
                // 文件读取结束
                break;
            }
            // 此时已经读到一部分数据, 放到 buffer 里, 把 buffer 中的内容写到响应对象中
            outputStream.write(buffer);
        }
        fileInputStream.close();
        outputStream.close();
    }
}

三、项目改进办法

1、基于白名单的防盗链机制

通过HTTP中的refer字段判定是否是指定网站请求图片,你想允许谁访问,就把链接地址加进来,

static private HashSet<String> whiteList = new HashSet<>();

    static {
        whiteList.add("http://127.0.0.1:7070/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\": \"wei shouquan de fangwen\" }");
            return;
        }*/

2、基于 MD5 实现相同内容图片只存一份

整体思路
1.修改上传图片代码, 使用 md5 作为文件名.
2.修改 DAO 层代码, 在 DAO 层实现一个 selectByMD5 方法, 根据 MD5 来查找数据库中的图片信息.
3.修改上传图片代码, 存储文件时先判定, 该 md5 对应的文件是否存在, 存在就不必写磁盘了.
4.修改删除图片代码, 先删除数据库记录, 删除完毕后, 看数据库中是否存在相同 md5 的记录. 如果不存在, 就删除磁盘文件.

 public 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;
    }

四、对项目的具体测试

1、单元测试

先要引入第三方依赖库Junit

<dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>

单元测试的代码

public class ImageDaoTest {

    @Test
    public void insert() {
        //图片有属性进行测试
        Image image=new Image();
        image.setImageName("test.jpg");
        image.setSize(1024) ;
        image.setUploadTime("2020-07-01");
        image.setContentType(" image/png") ;
        image.setPath("./image/d54c32d23621fb9ba448c71f1996c871");
        image.setMd5("d54c32d23621fb9ba448c71f1996c871");
        ImageDao imageDao=new ImageDao();
        imageDao.insert(image);
        //图片为空测试
        Image kong=new Image();
        imageDao.insert(kong);
    }

    @Test
    public void selectAll() {
        ImageDao imageDao=new ImageDao();
        ArrayList<Image> lists= (ArrayList<Image>) imageDao.selectAll();
        for(Image image:lists){
            System.out.println(image.getImageName());
        }
    }

    @Test
    public void selectOne() {
        ImageDao imageDao=new ImageDao();
        //id存在
        Image image1=imageDao.selectOne(113);
        System.out.println(image1.getImageName());
        //id不存在(报错--空指针异常)
        //Image image2=imageDao.selectOne(1);
        //System.out.println(image2.getImageName());
    }

    @Test
    public void delete() {
        ImageDao imageDao=new ImageDao();
        //id存在
        imageDao.delete(24);
        //删除不存在的id(报错)
        //imageDao.delete(1);
    }

    @Test
    public void selectByMd5() {
        ImageDao imageDao=new ImageDao();
        //md5存在
        Image image=imageDao.selectByMd5("e27dd4d4ad59d838e9f8ee0b5e382cfb");
        //Image image2=imageDao.selectByMd5("4c32d23621fb9ba448c71f1996c871");
        //md5不存在(报错)
        System.out.println(image.getImageName()+image.getImageId());
        // System.out.println(image2.getImageName()+image2.getImageId());
    }
}

2、界面测试

布局
1、图片比较多时,每一行最多五张图片,剩下的折行展示
2、每张图篇的大小一-致,都是200px* 200px
3、每一张图片都在一个div框里面,图片左下角有图片名称,删除按钮
4、 每一页最上面是logo,标题,接下来右边是图片上传按钮,最后一部分展示的是已经上传到服务器上的图片。
文字部分
1、字体的大小、字体的粗细、是否斜体展示、展示的位置
2、字体是否成功展示、页面上图片文件的名称是否按照设置的大小,字体形式展示
图片部分
1、图片是否完全展示,即上传的图片和展示的图片内容致
2、每一行的图片个数相等,展示风格-一致
3、点击图片本身可以放大图片
4、图片的放大.点击图片右边的放大按钮,也可以放大图片
5、可以连续查看放大图片
6、页面最多展示多少张图片

3、 功能测试

上传功能
1、点击选择上传按钮,可以出现电脑中资源选择的页面
2、点击选择上传按钮,可以出现电脑中资源选择的页面,选中一张图片,点击打开按钮,方框中"未选择任何页面”–>"图片名称”
3、点击上传按钮,页面会刷新,展示出刚刚上传的图片。存放图片的位置会有新的文件出现。数据库中会插入一条新的数据
4、上传图片格式为JPG,PNG格式的图片均可以上传成功
5、不选择任何文件,直接点击上传,应该有提示”请您选择一张图片”,
6、上传整个文件夹,无法上传,只会打开该文件夹,无法上传文件夹
7、不允许一次性上传多个文件(无法选中多个图片文件
8、上传文件大小大于磁盘空间剩余大小,提示"磁盘空间不足,上传 失败!
9、磁盘空间剩余0上传文件,提示”磁盘空间不足,上传 失败!
10、上传除 了图片以外的其他类型的图片,上传失败,比如doc、ppt、安装程序。
11、无法进行批量上传图片
12、上传不存在的图片
13、上传 一个图片名称和数据库中图片名称相同、内容不同
14、上传 一个图片名称和数据库中图片名称相同、内容不同图片名称相同,图片内容不同
删除功能
1、选择某一张图片下面的删除功能,点击,会出现提示删除弹框,点击确定,图片成功从页面上移除·
2、不能进行批量删除.(有删除全部图片按钮)
3、删除某一-张图片之后,页面整体图片为会发生重新排版
4、删除图片后,在服务器存放图片的路径下,该图片是否消失
5、删除图片后数据库中存放该图片的数据也相应被删除
6、删除相同名称的其中一个图片,不会对其它名称相同的图片产生影响。
7、删除名称相同,图片内容也相同的图片中-一张图片,对和该图片相同的图片不会产生影响
异常情况
1、数据库服务未启动,上传文件失败
2、弱网(不同网络的情况下) . 图片加载、上传和展示功能
3、加载(展示)已经损坏的文件,web前端页面不再展示,比如文件名称被篡改或者文件本身损坏
4、在上传的过程中,停止tomcat,查看是否上传成功

4、性能测试

从点击按钮到提交在三秒以内,符合358原则

5、兼容性测试

1、各种浏览器访问均可正常操作(搜狗、谷歌、IE、火狐、360)
2、相同浏览器的不同版本
3、不同的操作系统、苹果、linux、windows7 10 xp

6、安全性测试

1、防止sql注入
2、上传带有病毒的文件
3、超过图片超过最大限值时服务器会不会崩溃

7、易用性测试

1、上传图片时,只要选中图片即可图片输入框,即可上传图片,不一定非是按钮
2、页面功能按钮设计的直观易用

8、自动化测试

from selenium import webdriver
import unittest
import time
class imageTest(unittest.TestCase):
    def setUp(self):
        self.driver=webdriver.Chrome()
        self.driver.get("http://localhost:8081/image_server/index.html")
        self.driver.maximize_window()

    def tearDown(self):
       self.driver.quit()

    def test_upload(self):
       self.driver.find_element_by_name("upload").send_keys("C:\\Users\\11506\\Pictures\\2017-05\\03演示图片.jpg")
       time.sleep(3)
       self.driver.find_element_by_xpath("//*[@id='blog-collapse']/form/div[2]").click()
       time.sleep(3)

    def test_delete(self):
        self.driver.find_element_by_xpath("//*[@id='container']/div[1]/button").click()
        alert=self.driver.switch_to.alert()
        alert.accept()
    if __name__=="__main__":
        unittest.main()

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值