【图片服务器】实现思想代码+具体测试
文章目录
一、项目概述
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()