继续上周的django后台搭建,经过讨论选择不使用mysql数据库存储用户上传证件照信息,直接通过base64转码的形式在后台处理并返回前端直接通过数据流预览并实现图片下载
伙伴给我了相关base64的代码片段,通过整理,如下
def get_image(request):
if request.method == 'POST':
image = request.FILES['image']
open_id = request.POST.get('openid')
# print(open_id)
# return HttpResponse(open_id)
basedir = '/Users/shall/PycharmProjects/cqc_01'
path = basedir + '/static/images/'
if not os.path.exists(path + open_id + '.jpg'):
with open(path + open_id + '.jpg', 'wb') as f:
f.write(image.read())
f.close()
img_im = cv2.imread("static/images/" + open_id + '.jpg') # 要被base转换的图片地址
receive_base = base64.b64encode(cv2.imencode('.jpg', img_im)[1]).decode() # 把转换的编码赋值
print(receive_base) # 17292 #返回图片的base码的字母个数
return HttpResponse('上传成功')
else:
return HttpResponse("您已上传过图片")
这里默认是当前路径下不存在该用户已经上传过的图片,于是就写入图片,通过cv2的图片编码和base64的解码可以得到图片的base64编码
而这样是不符合实际情况的,经过讨论我们得出应该让用户重复上传后,只存用户最后一次上传后的图片,所以直接将if-else语句删除,如下
with open(path + open_id + '.jpg', 'wb') as f:
f.write(image.read())
f.close()
img_im = cv2.imread("static/images/" + open_id + '.jpg') # 要被base转换的图片地址
receive_base = base64.b64encode(cv2.imencode('.jpg', img_im)[1]).decode() # 把转换的编码赋值
print(receive_base) # 17292 #返回图片的base码的字母个数
return HttpResponse('上传成功')
这样static/images下就只会有一张图片,该图片命名唯一,为用户open_id+’.jpg’
解释为什么要删除if语句:
if语句的职能是判断当前路径下是否存在该图片,如果不存在,我就执行写入以及后面的操作,然而不管路径下是否是第一次写入还是之后写入的图片都需要进行转码,也就是后面几行的操作,所以去掉if后,不管是第几次提交,都将该路径下的文件覆写,这样就省去很多步骤,最后的结果还是一样的
https://www.jianshu.com/p/354a7cbe1efd
https://www.cnblogs.com/china-fanny/p/11213746.html
https://blog.csdn.net/loovelj/article/details/92833070
在这个步骤之前,伙伴给了我几个链接,我大概看了一下,然后相互讨论,比较cv2和矩阵法的优劣,发现通过cv2处理更优,但是通过实践发现并不需要在后端处理base64,可以直接通过HttpResponse返回base64编码,前端通过base64编码显示图片
然后就得到res.data的值为base64编码
整个代码段的代码如下
def get_image(request):
if request.method == 'POST':
image = request.FILES['image']
open_id = request.POST.get('openid')
# print(open_id)
# return HttpResponse(open_id)
basedir = '/Users/shall/PycharmProjects/cqc_01'
path = basedir + '/static/images/'
with open(path + open_id + '.jpg', 'wb') as f:
f.write(image.read())
f.close()
img_im = cv2.imread("static/images/" + open_id + '.jpg') # 要被base转换的图片地址
receive_base = base64.b64encode(cv2.imencode('.jpg', img_im)[1]).decode() # 把转换的编码赋值
print(receive_base) # 17292 #返回图片的base码的字母个数
return HttpResponse(receive_base)
wx.chooseImage({
count: 1,
sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
success: function (res) {
// 返回选定照片的本地文件路径列表,tempFilePath可以作为img标签的src属性显示图片
const tempFilePaths=res.tempFilePaths
console.log(tempFilePaths)
console.log(that.data.openid)
wx.uploadFile({
filePath:tempFilePaths[0],
name: 'image',
url: 'http://127.0.0.1:8000/app/get_image/',
method:'POST',
header:{
'content-type':'application/x-www-form-urlencoded'
},
formData:{
openid:that.data.openid
},
success: res => { // 调用成功时的回调函数
console.log('[上传文件] 成功:', res)
wx.showToast({
title: '上传成功',
icon:'success'
})
/*******主要部分********/
console.log(res.data)
var base64Img = res.data
var imgData = base64Img.replace(/[\r\n]/g, '')
that.setData({
imgData: imgData
})
/*********************/
},
fail: e => { // 调用失败时的回调函数
console.error('[上传文件] 失败:', e);
wx.showToast({ // 显示消息提示框
icon: 'none',
title: '上传失败',
})
},
complete: () => { // 调用完成时的回调函数
wx.hideLoading() // 隐藏加载提示框
}
})
that.setData({
files: that.data.files.concat(res.tempFilePaths)
});
if (that.data.hidden='false'){
console.log(that.data.hidden)
that.setData({
hidden:true
})
}
}
})
其中js代码中的res.data即为HTTPResponse上传的base64编码的值,然后通过setData绑定页面数据,从而通过以下模板获取img的显示
<image src="data:image/jpg;base64,{{imgData}}">image>
然后这样前端页面就会显示我们传上去的图片
下载图片是通过base64直接显示到前端的图片进行下载处理,js代码如下
showTopTips:function(e){
let code =this.data.imgData; // 后台返回的base64图片,没有带data:image/png;base64,的前缀。
let src = `data:image/jpg;base64,${code}`;
const fsm = wx.getFileSystemManager(); // 获取文件管理器
code = code .replace(/\ +/g, ""); //去掉空格方法
code = code .replace(/[\r\n]/g, "");//去掉回车
const buffer = wx.base64ToArrayBuffer(code ); // 将 base64 字符串转成 ArrayBuffer 对象
const fileName = wx.env.USER_DATA_PATH + '/share_img.jpg'; // 文件系统中的用户目录路径 (本地路径)
/**
* @param fileName: 文件路径
* @param buffer : 要写入的文本或二进制数据
* @param binary: 指定写入文件的字符编码
*/
fsm.writeFileSync(fileName, buffer, 'binary'); // 写入文件, 同步方法
console.log(fileName); // 写入成功后就可以访问到该图片路径了
let self = this
// 相册授权
wx.getSetting({
success(res) {
// 进行授权检测,未授权则进行弹层授权
if (!res.authSetting['scope.writePhotosAlbum']) {
wx.authorize({
scope: 'scope.writePhotosAlbum',
success () {
wx.saveImageToPhotosAlbum({
filePath: fileName,
success (res) {
wx.showToast({
title: '保存成功',
icon: 'success',
duration: 2000
})
}
})
},
// 拒绝授权时,则进入手机设置页面,可进行授权设置
fail() {
wx.openSetting({
success: function (data) {
console.log("openSetting success");
},
fail: function (data) {
console.log("openSetting fail");
}
});
}
})
} else {
// 已授权则直接进行保存图片
wx.saveImageToPhotosAlbum({
filePath: fileName,
success (res) {
wx.showToast({
title: '保存成功',
icon: 'success',
duration: 2000
})
}
})
}
},
fail(res) {
console.log(res);
}
})
}
这样当点击上传图片后,后端通过接收图片,处理图片,返回处理好的图片的base64码,前端显示该效果图片,用户可以选择下载保存该图片到相册,整个功能就这样实现
有一点要注意的是,我一开始选择预览或者真机调试,这两种方法都没办法在手机端得到服务,因为手机端并没有本地后台进行处理,没有开通8000端口进行服务,这一点有点犯天真了
前端要通过小程序界面进行证件照的颜色和尺寸的选择
<a class="weui-grid">
这是一个尺寸选择的按钮
<a class="weui-grid">
<button class='{{colorbtns[1].checked?"checked_colorbutton2":"normal_colorbutton2"}}' data-id='{{colorbtns[1].id}}' bindtap='radiocolorButtonTap'>
button>
a>
这是一个颜色选择的按钮
在js处理页面需要一些代码进行处理,一起开发的伙伴的js写得非常清楚,这里我直接给出,这是他的主页链接,大家也可以去查看关注,https://me.csdn.net/qq_44933075
首先,在页面加载时要绑定一些值
onLoad: function (options) {
this.data.openid=wx.getStorageSync('opid')
console.log(this.data.openid)
this.data.buttons[0].checked = true; //初始尺寸
this.data.colorbtns[0].checked = true; //初始颜色
this.data.imgcolor= this.data.colorbtns[0].name //初始传输的尺寸值
this.data.imgsize=this.data.buttons[0].name//初始传输的颜色值
this.setData({
buttons: this.data.buttons, //赋值颜色
colorbtns: this.data.colorbtns //赋值尺寸
})
},
这些值可以供后端获取
选择尺寸的bindtap函数
radioButtonTap: function (e) {
console.log(e)
let id = e.currentTarget.dataset.id //id为选择尺寸值
console.log(id)
for (let i = 0; i < this.data.buttons.length; i++) { //判断尺寸选择了哪个
if (this.data.buttons[i].id == id) {
this.data.imgsize=this.data.buttons[i].name
//当前点击的位置为true即选中
this.data.buttons[i].checked = true; //把值设为true
}
else {
//其他的位置为false
this.data.buttons[i].checked = false; //其他位置为flase
}
}
this.setData({
buttons: this.data.buttons,
msg: "id:"+id
})
}
选择颜色的bindtap函数
radiocolorButtonTap: function (e) {
console.log(e)
let id = e.currentTarget.dataset.id
console.log(id)
for (let i = 0; i < this.data.colorbtns.length; i++) {
if (this.data.colorbtns[i].id == id) {
//当前点击的位置为true即选中
this.data.colorbtns[i].checked = true;
this.data.imgcolor= this.data.colorbtns[i].name
console.log(this.data.imgcolor);
}
else {
//其他的位置为false
this.data.colorbtns[i].checked = false;
}
}
this.setData({
colorbtns: this.data.colorbtns,
msg: "id:"+id
})
},
之前我们只是获取到了openid,在添加了上述js代码后,就需要对后台获取的数据进行相应添加
def get_image(request):
if request.method == 'POST':
image = request.FILES['image']
open_id = request.POST.get('openid')
imgcolor = request.POST.get('imgcolor')
imgsize = request.POST.get('imgsize')
# print(open_id)
# return HttpResponse(open_id)
# basedir = '/Users/shall/PycharmProjects/cqc_01'
basedir = os.path.dirname(os.path.dirname(__file__))
path = basedir + '/static/images/'
with open(path + imgcolor + open_id + '.jpg', 'wb') as f:
f.write(image.read())
f.close()
img_im = cv2.imread("static/images/" + imgcolor + open_id + '.jpg') # 要被base转换的图片地址
receive_base = base64.b64encode(cv2.imencode('.jpg', img_im)[1]).decode() # 把转换的编码赋值
print(receive_base) # 17292 #返回图片的base码的字母个数
return HttpResponse(receive_base)
这样我们就获取到了所有我们需要的属性,然后在我们预设好的处理图片的函数中进行调用和执行,这块处理接口是另外一位伙伴去实现,这里在整个服务器搭建完成后会进行完整记录
首先我先去腾讯云购买了1个月的学生优惠服务器,只需要10元,学生党可以去购买尝试,放链接https://cloud.tencent.com/act/campus
我买的是centos,也就是linux环境下的服务器,因为自己的电脑是mac类linux系统,可以直接在终端连接服务器,比较方便,大家可以根据自己的系统去选择linux、windows或其他系统
打开云服务器界面,选择ssh密钥,新建一个密钥绑定你选择的实例,然后如果实在mac系统里,可以在终端运行
ssh -i "密钥的绝对路径" root@'公网ip'
然后会看到成功进入服务器命令界面
以上是通过自己购买的服务器直接进入的方法
以下是通过docker虚拟机进入界面,就是用docker挂载linux镜像,并在该镜像下下载宝塔管理工具,以下操作为mac系统的操作
首先如果你有homebrew,可以使用命令brew cask install docker
下载docker,或者也可以去官网下载
然后docker换源,打开设置页,更改如下设置然后重新启动docker
这时候就可以进行镜像拉取
docker pull centos:7
宝塔6.x是针对centos7.x,所以建议不要拉去latest版本
然后映射容器端口
docker run -d -it -p 8888:8888 centos
然后查看该容器id,启动
docker ps
docker exec -it [容器ID] bash
这样就会进入linux系统的终端命令界面,这时候就可以使用yum安装宝塔
yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh
静静等待成功安装,安装完成它会显示内网IP和用户名密码,可以登录进行查看
以上两种方法均可
然后要进行域名申请,同样是在腾讯云中申请一个域名,我自己测试用所以申请了一个8块钱一年的.site域名,需要身份信息进行验证,拿到域名地址后,在宝塔界面中添加相应站点,申请SSL证书,需要保证你填入的域名拥有对应的DNS解析,也就是域名已经成功申请下来
给大家放一个官方指导文章,https://www.django.cn/article/show-30.html,这个文章手把手教学如何简单的使用宝塔工具部署django项目到linux服务器中
我自己在完成这个发布的时候,遇到的问题就是一定要放行你配置里填入的端口,我按照文档中写的是8897端口,放行后,直接使用IP:8897的方式可以访问到自己部署的项目,这样整个流程就算完成了
这里的error为我自己定义访问/app的默认httpresponse