Vue + SpringMVC实现像微信朋友圈发动态的功能
平时我们都有玩过微信发朋友圈动态这样的功能吧,你知道它可以写入文字还可以上传一些我们想要发表的图片而且发表的图片还可以是很多张,但是这个时候我们有没有想过这些看起来简单的操作那它们是怎么实现的呢,这就是我要写这篇博客的原因了。由于本人前段时间采用Vue框架做了一个旅游APP而后台则是采用了java的SSM框架。其中这个App中有一个功能模块是用户可以对景点发表一些评论或者攻略的,我就把的这个功能模仿了微信发朋友圈动态的功能。话不多说了,接下来就是直接上代码吧。
- 先看前端的代码
//我是引用了蚂金服的前端组件库https://vue.ant.design/docs/vue/use-with-vue-cli-cn/
//所以我们要先下载这些资源
$ npm install ant-design-vue --save
====================================================================================
<template>
<div class="comment">
<div>
<div class="regist_header">
景区评论发表区
</div>
</div>
<div class="comment_desc">
星级分数:<a-rate :defaultValue="0" @change="starCount" allowHalf />
<a-comment>
<div slot="content">
<a-form-item>
<a-textarea :rows="4" @change="descChange" :value="value" ></a-textarea>
</a-form-item>
<div class="img">
<div class="demo-upload-list" v-for="item in uploadList" :key="item.index">
<template v-if="item.status === 'finished'">
<img :src="item.url">
<div class="demo-upload-list-cover">
<Icon type="ios-eye-outline" @click.native="handleView(item.url)"></Icon>
<Icon type="ios-trash-outline" @click.native="handleRemove(item)"></Icon>
</div>
</template>
<template v-else>
<Progress v-if="item.showProgress" :percent="item.percentage" hide-info></Progress>
</template>
</div>
<Upload
ref="upload"
:show-upload-list="false"
:default-file-list="defaultList"
:on-success="handleSuccess"
:format="['jpg','jpeg','png']"
:max-size="2048"
:on-format-error="handleFormatError"
:on-exceeded-size="handleMaxSize"
:before-upload="handleBeforeUpload"
multiple
type="drag"
action="http://192.168.1.100:8200/mavenView_war_exploded/ar/uploadFile.action"
:data= '{type:"comment", user_id:this.user.id, city:this.information.city, scenery:this.information.scenery_title}'
style="display: inline-block;width:100px;">
<div v-if="!(this.uploadList.length >= 6)" style="width: 100px;height:100px;line-height: 100px;">
<Icon type="ios-camera" size="20"></Icon>
</div>
</Upload>
<Modal title="View Image" v-model="visible">
<img :src="imgName" v-if="visible" style="width: 100%">
</Modal>
</div>
<a-form-item>
<a-button
id="add_comment"
htmlType="submit"
:loading="submitting"
@click="handleSubmit"
type="primary"
>
发表评论
</a-button>
</a-form-item>
</div>
</a-comment>
</div>
</div>
</template>
<script>
import 'ant-design-vue/dist/antd.css'//蚂蚁金服组件库
import Antd from 'ant-design-vue'//蚂蚁金服组件库
import moment from 'moment'
import fastClick from 'fastclick'
import { mapState } from "vuex"
import axios from 'axios'
import qs from 'qs'
export default {
name: 'Criticism',
data () {
return {
defaultList: [],
imgName: '',
visible: false,
uploadList: [],
comments: [],
submitting: false,
value: '',
moment,
count: 0,
number: 0,
imgNum: 0
}
},
methods: {
handleView (url) {
this.imgName = url;
this.visible = true;
},
handleRemove (file) {
const fileList = this.$refs.upload.fileList;
this.$refs.upload.fileList.splice(fileList.indexOf(file), 1);
// 往对应路径的发起ajax数据请求
axios({
method: 'post',
url: 'http://localhost/mavenView_war_exploded/ar/deleteUpdate.action',
data:qs.stringify({fileUrl: file.url})
}).then(this.getDataSucc)
},
handleSuccess (res, file) {
console.log(res)
if(res.ret){
file.url = res.data.url
file.name = res.data.name
}
},
handleFormatError (file) {
this.$Notice.warning({
title: 'The file format is incorrect',
desc: 'File format of ' + file.name + ' is incorrect, please select jpg or png.'
});
},
handleMaxSize (file) {
this.$Notice.warning({
title: 'Exceeding file size limit',
desc: 'File ' + file.name + ' is too large, no more than 2M.'
});
},
handleBeforeUpload (file) {
console.log(file)
const check = this.uploadList.length < 6;
if (!check) {
this.$Notice.warning({
title: '发图存量最大为6张!'
});
}
return check;
},
starCount(value, index) {
console.log(index)
this.count = value
},
imgSub(id) {
const list = []
for(var i=0; i<this.fileList.length; i++) {
if(this.fileList[i].id != id) {
list.push(this.fileList[i])
}
}
this.fileList = list
this.imgNum = list.length
console.log(id)
},
openNotification (res) {//操作提示窗口
if (res == 'success') {
this.$notification.open({
message: '恭喜您,评论发表成功!',
description: '您可以返回到个人页面进行查看评论!',
duration: 3,
})
}else if(res == 'login') {
this.$notification.open({
message: '跳转失败,可能失败原因!',
description: '您还未进行用户登录,请前去登录账户!',
duration: 3,
});
} else if(res == 'photo') {
this.$notification.open({
message: '选图失败,请重新选择图片!',
description: '您选择的图片不得超过6张,请重新输入!',
duration: 3,
})
} else {
this.$notification.open({
message: '评论发表失败,请重新发表!',
description: '请把内容填写完整,请重新输入发表内容!',
duration: 3,
})
}
},
handleSubmit() {
if (!this.value) {
return;
}
const values = {}
values.city = this.information.city
values.scenery_title = this.information.scenery_title
values.nickname = this.user.nickname
values.comment = this.value
values.user_id = this.user.id
values.count = this.count
values.imgNum = this.fileList.length
// 往对应路径的发起ajax数据请求
axios({
method: 'post',
url: 'http://localhost:8200/mavenView_war_exploded/insert/Comment.action',
data:qs.stringify(values)
}).then(this.getDataSucc)
},
getDataSucc (res) {
// 获取数据对象
console.log(res);
res = res.data
// 判断数据对象是否存在
if (res.code == 0) {
this.openNotification('success')
} else {
this.openNotification('error')
}
},
descChange(e) {
this.value = e.target.value
},
},
mounted() {
this.uploadList = this.$refs.upload.fileList
},
computed: {
...mapState(['information','id','user'])
}
}
</script>
<style lang="stylus" scoped>
>>> .ant-list-split .ant-list-item {
float: right
height: 100%
}
>>> .ant-comment-inner{
max-width: 100%
}
.comment {
width: 100%
height: 100%
.regist_header {
width: 100%
line-height: 1.5rem
text-align: center
font-size: 0.5rem
background: #00afc7
color: #fff
}
.comment_desc {
width: 100%
height: 11rem
padding: 0.2rem
.img {
.demo-upload-list{
display: inline-block;
float: left
margin: 0.06rem 0.1rem
width: 30%
height: 2rem
text-align: center;
line-height: 2rem;
border: 1px solid transparent;
border-radius: 4px;
overflow: hidden;
background: #fff;
position: relative;
box-shadow: 0 1px 1px rgba(0,0,0,.2);
// margin-right: 4px;
}
.demo-upload-list img{
width: 100%;
height: 100%;
}
.demo-upload-list-cover{
display: none;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: rgba(0,0,0,.6);
}
.demo-upload-list:hover .demo-upload-list-cover{
display: block;
}
.demo-upload-list-cover i{
color: #fff;
font-size: 20px;
cursor: pointer;
margin: 0 2px;
}
.img_wipper {
float: left
margin: 0.06rem 0.1rem
width: 30%
height: 2rem
// height: 2.14rem
background:red
.img_wipper_url {
position: absolute
// z-index: 2
width: 30%
height:2rem
}
.img_wipper_sub {
z-index: 5
position: relative
width: 0.6rem
line-height: 0.6rem
text-align: center
float: right
}
}
}
}
>>>.ant-comment-avatar {
margin-right: 0rem;
}
}
</style>
- 然后是SpringMVC的后台代码
/**
* 功能分析:完成对前端文件上传的请求,接收图像,修改图像,存储图片的功能
*
* @param request //接收请求体
* @param file //上传的文件
* @return
*/
//多图片上传控制器
@RequestMapping("/uploadFile")
@ResponseBody
public JSONObject uploadFile(HttpServletRequest request, @RequestParam("file") MultipartFile file){
JSONObject json = new JSONObject();
//设置同步代码块
synchronized (this) {
Map<String, Object> map = new HashMap<>();
Boolean flag=false;
//判断是否有图片上
if(file.isEmpty()){
json.put("ret", false);
json.put("code", 2);
return json;
}
try{
//获取上传文件的名称
String fileName = file.getOriginalFilename();
//获取文件上传的时间戳
DateFormat format1 = new SimpleDateFormat("yyyyMMddhhmmss");
String dateStr = format1.format(new Date()) + Math.floor(Math.random()*10000);
//设置上传文件在服务器端的存储路径
String path = request.getServletContext().getRealPath("/static/")+dateStr;
//存储路径和上传文件名生成一个文件
File dest = new File(path, fileName);
//判断文件父目录是否存在
if(!dest.getParentFile().exists()){
//不存在就创建一个文件夹出来存储上传文件
dest.getParentFile().mkdir();
//将上传文件保存到一个目标文件中
// file.transferTo(new File(path + File.separator + fileName));
//通过图片的IO流读取上传的图片资源
BufferedImage image = ImageIO.read(file.getInputStream());
//获取一个操作图像资源的镀锡
BufferedImage images = null;
//定义上传图片的高、宽值的变量
int img_width = 610,img_height = 400;
if (image != null) {//如果image=null 表示上传的不是图片格式
//创建一个存放图片区域的对象
images = new BufferedImage(img_width, img_height, BufferedImage.TYPE_INT_BGR);
//创建一个 Graphics2D,可以将它绘制到此 BufferedImage 中。
Graphics garphics = images.createGraphics();
/**
* 绘制当前可用的指定图像的指定区域,动态地缩放图像使其符合目标绘制表面的指定区域。
* 简单点说就是对上传的图像进行宽度和高度的修改从而达到符合我们前端的展示的需要
*/
garphics.drawImage(image, 0, 0, img_width, img_height, null);
//创建一个文件输出流
OutputStream outputStream = new FileOutputStream(dest);
//把修改好的图片按指定输出流的路径存储
JPEGImageEncoder j = JPEGCodec.createJPEGEncoder(outputStream);
j.encode(images);
outputStream.close();
}
}
if(dest.exists()){
map.put("name", fileName);
map.put("url", dataUrl);
json.put("ret",true);
json.put("data", map);
json.put("code", 0);
} else {
json.put("ret", false);
json.put("code", 2);
}
System.out.println("数据库路径:"+dataUrl);
}catch(Exception e){
e.printStackTrace();
json.put("ret", false);
json.put("code", 2);
}
return json;
}
}
/**
* 功能分析:可以完成对一些失去价值的图像资源进行回收内存操作
*
* @param request
* @return
*/
//清除用户取消的图片
@RequestMapping("/deleteUpdate")
@ResponseBody
public JSONObject deleteImg(HttpServletRequest request) {
JSONObject json = new JSONObject();
String url = request.getParameter("fileUrl");
if (url == null) {
return json;
}
//删除数据库中的记录
CityImg cityImg = urdi.findCityImgByUrl(url);
if (cityImg != null) {
int number = urdi.DeleteCityImg(cityImg.getId());
}
String[] fileArr=url.split("/");
String fileName = fileArr[fileArr.length-1];
String path = request.getServletContext().getRealPath("/static/")+fileArr[fileArr.length-2];
File dest = new File(path, fileName);
//删除磁盘目录下的记录
if (dest.exists()){
//如果该目录的文件存在,执行删除操作
dest.delete();
}
return json;
}
好了这就是一个完整的类似微信发朋友圈动态功能模块了