一、前端
1.前端框架
vue jquery
2.前端执行流程
(1)获取图片列表
a.以下语句在script中,所以在页面初始化时就会执行,调用vue变量appd的getImage()函数
app.getImages();
b.在getImage()函数中发送ajax请求,接口的请求方法是GET,路径是image,响应成功将响应数据赋值给vue中的数组变量images(this指的就是vue对象),images数组刚开始是空的
<script>
var app = new Vue({
el:'#app',
data: {
images: [
],
uploadImage: ''
},
methods: {
getImages() {
$.ajax({
url: "image",
type: "get",
context: this,
success: function(data, status) {
this.images = data;
$("#app").resize();
}
})
c.此时vue双向绑定,当images数组发生改变对应的页面利用for循环获取到图片列表
(2)删除
删除按钮点击后,调用remove函数(传入imageId),发送ajax请求,响应状态码为200就刷新图片列表,提示删除成功
remove(imageId) {
$.ajax({
url:"image?imageId=" + imageId,
type:"delete",
context: this,
success: function(data, status) {
app.getImages();
alert("删除成功");
}
})
}
(3)选择文件
form标签中input type=file是页面中的选择文件,点击后选择一个文件(发生改变),会触发change事件,进入changeImage函数,将文件数据赋值给uploadImage变量,以便上传函数判断
<form class="am-topbar-form am-topbar-right am-form-inline" v-on:submit.prevent="imageUpload()">
<div class="am-form-group">
<input type="file" v-on:change="changeImage($event)" class="am-form-field am-input-sm">
</div>
<div class="am-form-group">
<input type="submit" class="am-form-field am-input-sm" style="height:41px" value="上传"/>
</div>
</form>
(4)上传图片
form标签中的input type=submit点击,就会发生表单提交事件,此时v-on:submit.prevent是禁止表单自动提交,而是要通过绑定的vue变量的imageUpload函数
根据changeImage函数中赋值过的uploadImage变量来判断是否选择了图片后进行的上传,如果该变量是空的,会弹出警告窗口提示“选择图片后上传”;如果非空,则构建formData对象,设置请求体,请求数据格式就是form-data;上传成功(即ok=true)后,调用getImages函数刷新图片列表,上传失败报错
imageUpload(){
if(!app.uploadImage) {
alert("选择图片后上传");
return;
}
let data = new FormData();
data.append("uploadImage", app.uploadImage);
$.ajax({
url: "image",
type: "post",
processData: false,
contentType: false,
data: data,
// context: this,
success: function(data, status) {
if(data.ok){
app.getImages();
}else{
alert(data.msg);
}
// alert("上传成功");
},
error: function (err, textStatus, throwable) {
console.error(JSON.stringify(err))
}
})
}
二、后端
1.后端技术
servlet、jdbc、jackson、 commons-codec(apche提供的专门加密的,提供一系列api通过加密算法生成密文、校验。这个项目是用来生成md5,用来验证图片的唯一性)
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.13</version>
</dependency>
2.工具类
1)DBUtil(数据库连接工具类)
(1)封装数据库连接池(双重校验锁的线程安全的单例模式)方法:
a.volatile修饰的静态变量
b.两个if判断,中间进行synchronized加锁操作保证安全
(2)关闭连接
2)json操作工具类(WebUtil)
3.文件上传功能
提供图片上传接口:
a.获取请求数据,获取图片part对象(属于复杂数据,采用Part,将数据保存在服务端本地硬盘和数据库中,在保存之前要先验证md5值在数据库中是否存在,如果存在则是重复图片则不用保存。
b.保存在服务端本地硬盘
根据获取的请求数据,利用md5Hex方法生成md5值
String md5= DigestUtils.md5Hex(p.getInputStream());
p.write(LOCAL_PATH_PREFIX+"/"+md5);
c.保存在数据库
先构造一个ImageInfo对象,保存插入数据库的数据;
设置图片名、大小、上传日期、md5、数据格式、路径;
进行插入数据库操作,调用ImageDao的insert,将图片数据插入;
d.返回响应数据,根据前端代码需要两个数据(ok,msg),转换为json返回
获取图片列表接口:
调用ImageDao的selectAll获取数据库中的所有图片数据,多行数据转换为List<ImageInfo>,并设置响应体
此时运行,并不会显示图片内容。
显示图片内容接口:ImageShowServlet
4.删除图片
在ImageServlet中写删除图片接口,要删除数据库中的和本地硬盘中的图片文件
5.解决图片重复上传问题:比较md5值
上传重复的数据,数据库会新增数据,本地硬盘虽然不会新增文件,但是进行了覆盖式的写入数据,会导致性能变差
在生成md5值后,根据数据库查询操作验证,如果重复则弹出警告框提示
String md5= DigestUtils.md5Hex(p.getInputStream());
//根据md5值在数据库查询是否存在,存在返回报错信息
ImageInfo imageInfo=ImageDao.selectByMd5(md5);
//图片已存在
if(imageInfo!=null){
Map<String,Object> data=new HashMap<>();
data.put("ok",false);
data.put("msg","上传的图片已存在");
WebUtil.serialize(resp,data);
return;
}
p.write(LOCAL_PATH_PREFIX+"/"+md5);
6. 防盗链
根据http请求refer请求头,可以知道http请求是哪个页面发起的,根据refer值判断是否允许访问
白名单:提供数组/列表,在范围内,可访问
黑名单:提供数组/列表,在范围内,不可访问
三、结果