前期背景
项目周期:2020.09.24-2020.09.29
使用的框架:Electron springboot
最终目的:做一个简易版的qq聊天的桌面软件
准备工作
1、安装node、配置node环境
2、安装vscode
3、安装vue-cli脚手架
以上三个步骤如果不会,可以看这个教程 https://blog.csdn.net/qq_37591637/article/details/89944336
4、安装Electron
5、初始化一个vue与Electron一身的项目
项目初始化模板成功以后,打开文件夹,进行npm install 安装必须的模块
等待这个项目所需安装模块都安装完毕以后,我们启动项目
npm run dev
但是报错 process is not defined
解决办法
修改你项目文件下.electron-vue
里面的webpack.renderer.config.js
和webpack.web.config.js
添加一段这个代码
//加一些参数配置
templateParameters(compilation, assets, options) {
return {
compilation: compilation,
webpack: compilation.getStats().toJson(),
webpackConfig: compilation.options,
htmlWebpackPlugin: {
files: assets,
options: options
},
process,
};
},
//加一些参数配置
整体的代码是这样的
new HtmlWebpackPlugin({
filename: 'index.html',
template: path.resolve(__dirname, '../src/index.ejs'),
//加一些参数配置
templateParameters(compilation, assets, options) {
return {
compilation: compilation,
webpack: compilation.getStats().toJson(),
webpackConfig: compilation.options,
htmlWebpackPlugin: {
files: assets,
options: options
},
process,
};
},
//加一些参数配置
minify: {
collapseWhitespace: true,
removeAttributeQuotes: true,
removeComments: true
},
nodeModules: false
}),
记住,两个文件的相同位置都要添加这个代码
然后保存,在控制台输入npm run dev
出现
第二部分、制作一个简约的页面,实现数据的前后交互
1、前端页面精美的库 element-ui库(html的)
cnpm install --save element-ui
2、 安装sass库(css的)
cnpm install --save-dev node-sass
cnpm install --save-dev sass-loader
在main.js里面加入全局变量的引用
//添加element-ui组件
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(ElementUI)
//添加element-ui组件
3、安装axios,用于调用http请求 一般在开始运行项目的时候npm install 就已经安装过了
这个时候,简单快速的布出精美的页面,就需要element-ui了
打开官网 https://element.eleme.cn/#/zh-CN/component/installation
我们先布局出一个登陆 注册的页面出来
打开element-ui这个组件网,选择我们需要的零件
这里有代码,也可以在线运行,我们把代码改成我们需要的,再复制到我们的项目里面来;
问题、代码灰色,没有高亮
但是我发现我项目里面的代码都是灰色的,没有高亮!
是因为没有安装vetur的缘故
选择vscode左侧的最下面的那个图标,输入Vetur 因为我一打开就有,直接点击install就可以了
安装成功以后,就没有绿色的install的按钮了
现在重启这个软件,不重启也可以;
代码已经高亮了!
我们写代码主要是在renderer文件夹的components里面新建vue文件,布局的
所以打开项目中vue文件(出了App.vue外),把原有的代码全部清除,只留下基本的标签
之所以留下一些注释的东西,是因为引导,我们如果需要在一个组件里面引入另一个组件的书写方式 ;
忘了说,一个vue文件就是一个组件
开始布局
我在element-ui官网找到表单,然后在在线运行里面更改成我需要的代码
然后拷贝相关的代码在vue组件里面
<template>
<div id="app">
<el-form ref="form" :model="form" label-width="80px">
<el-form-item label="用户名">
<el-input v-model="form.name"></el-input>
</el-form-item>
<el-form-item label="密码">
<el-input v-model="form.pass"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">立即登陆</el-button>
<el-button>取消</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
// import 其他vue组件的名称 from './LandingPage/其他vue组件的名称'
export default {
name: 'landing-page',
data(){
return{
form: {
name: '',
pass:'',
}
}
},
//导入其他的组件 components: { SystemInformation },
methods: {
onSubmit() {
console.log('submit!');
}
}
}
</script>
<style>
</style>
运行项目 npm run dev
是不是出来了呢?
而且,最方便的是,如果你代码有问题,不用终止项目,直接搞好保存就可以了,界面自动刷新!
我们现在要做的是
1、再美化页面 添加一个注册的页面
2、与后端以及数据库进行交互 实现登陆的功能(我用的语言是java 采用的是springboot框架)
3、打包前后端项目为桌面程序,安装看看(不需要jdk安装环境的exe程序)
美化页面 添加注册页面
这里涉及到多个路由文件的配置。index.js是主路由,但是随着项目的增大,以及方便管理,需要子路由文件;
路由之间的跳转
注册页面有一个登陆的按钮,点击登陆按钮就会跳转到login.vue文件里面
用 <router-link :to="{path:'这里是路由文件里面的路径'}"> </router-link>
现在要解决跨域问题
点击注册,登陆按钮,然后把值通过axios给后端,由于端口不同,项目名称不同,存在着跨域
我的后端是idea软件springboot项目
electron-vue项目跨域设置
在dev-runner.js里面添加跨域设置
/*
这里是跨域设置
*/
proxy: {
'/api': {
// 请求的目标服务器地址
target: 'http://localhost:8080/',
// 如果是https接口,需要配置这个参数
secure: false,
// 设置允许跨域
changeOrigin: true,
// 重写路径
pathRewrite: {
'^/api': ''
},
headers: {
referer: ''
}
}
},
//这里是跨域设置
是http不是https
我就是因为这里写错了,所以一直报错 HTTP method names must be tokens
在main.js里面全局设置axios
注意如果这里是axios,在其他的vue文件里面使用就是axios;如果是$axios的话,其他文件里面就是$axios;
进行跨域请求
onSubmit() {
//跨平台交互
// 发送一个 POST 请求
this.$axios({
method: 'post',
url: '/api/user/insert/',
header:{
'Content-Type':'application/json' //如果写成contentType会报错
},
data: {
username: 'Fred',
password: 'Flintstone',
tell:'17356286023'
},
}).then((res) => {
console.log(res)
});
//跨平台交互
}
}
后端是springboot
@RequestMapping("/insert")
public String adduser(@RequestBody String juser) throws JSONException {
//把字符串变成Json对象
System.out.println("接受到的数据是:"+juser);
JSONObject jo=new JSONObject(juser);
user u=new user();
u.setPassword(jo.getString("password"));
u.setTell(jo.getString("tell"));
u.setUsername(jo.getString("username"));
int i=us.insert(u);
return "index";
}
我们现在运行项目,看一下,是否能注册成功
哈哈哈,现在整个流程都跑通了.....
现在普及一个关于jsonobject jsonarray 以及表单数据 前后端如何发送与接受
上面我axios发送的是json数据,准确来说是jsonobject数据,后端用(@RequestBody String juser)接受的
1、axios发送一个json数组,后端的接受
this.$axios({
method: 'post',
url: '/api/user/insert/',
header:{
'Content-Type':'application/json' //如果写成contentType会报错
},
data:[{username:'简雍',password:'111',tell:'110'},{username:'糜竺',password:'123',tell:'119'},"true","蜀国初期人员"],
}).then((res) => {
console.log(res)
});
//跨平台交互
@RequestMapping("/insert")
public String adduser(@RequestBody String juser) throws JSONException {
JSONArray ja=new JSONArray(juser);
JSONObject JO=ja.getJSONObject(0);
System.out.println(JO.get("username")+"-"+JO.get("password")+"-"+JO.get("tell"));
JSONObject JO1=ja.getJSONObject(1);
System.out.println(JO1.get("username")+"-"+JO1.get("password")+"-"+JO1.get("tell"));
System.out.println(ja.get(2));
System.out.println(ja.get(3));
}
2、axios发送一个表单数据,后端的接受
// 发送一个 POST 请求
this.$axios({
method: 'post',
url: '/api/user/insert/',
header:{
'Content-Type':'application/x-www-form-urlencoded' //如果写成contentType会报错
},
data:this.qs.stringify({username:'刘备',password:'999',tell:'12365897452'}),
}).then((res) => {
console.log(res)
});
//跨平台交互
@RequestMapping("/insert")
public String adduser(@RequestParam String username,@RequestParam String password,@RequestParam String tell) throws JSONException {
//把字符串变成Json对象
System.out.println("---------"+username+"-----"+password+"-----"+tell);
}
总结
如果是json数据,不管是json数组还是json对象,axios中要设置 'Content-Type':'application/json',并且不需要qs转换;
后端用@RequestBody String juser 接受,然后转换为原本的类型,如json对象或json数组;
如果是单纯的键值对 'Content-Type':'application/x-www-form-urlencoded',用qs转换一下,然后在后端用
@RequestParam 一模一样的属性名称接受
如果json对象与json数组不懂的,可以看这个详细的教程案例
https://blog.csdn.net/qq_37591637/article/details/90319229
实现动态的注册、登陆功能
reg.vue
<template>
<div id="app">
<el-form :model="form" label-width="50px" class="mc">
<el-form-item >
<el-input v-model="form.name" placeholder="用户名/手机号码"></el-input>
</el-form-item>
<el-form-item >
<el-input v-model="form.pass" placeholder="密码"></el-input>
</el-form-item>
<el-form-item >
<el-input v-model="form.tell" placeholder="手机号码"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">立即注册</el-button>
<router-link :to="{path:'/'}"><el-button>登陆</el-button></router-link>
</el-form-item>
</el-form>
</div>
</template>
<script>
// import 其他vue组件的名称 from './LandingPage/其他vue组件的名称'
export default {
name: 'landing-page',
data(){
return{
form: {
name: '',
pass:'',
tell:''
}
}
},
//导入其他的组件 components: { SystemInformation },
methods: {
onSubmit() {
//跨平台交互
// 发送一个 POST 请求
console.log(this.form.name);
this.$axios({
method: 'post',
url: '/api/user/insert/',
header:{
'Content-Type':'application/x-www-form-urlencoded' //如果写成contentType会报错
},
data:this.qs.stringify({username:this.form.name,password:this.form.pass,tell:this.form.tell}),
}).then((res) => {
console.log(res)
});
//跨平台交互
}
}
}
</script>
<style>
/* #app{
background-image: url('~@/assets/img/bg1.jpg');
} */
.mc{
padding-top: 110px;
padding-left: 552px;
width: 400px;
}
</style>
login.vue
<template>
<div id="app">
<el-form :model="form" label-width="50px" class="mc">
<el-form-item >
<el-input v-model="form.name" placeholder="用户名/手机号码"></el-input>
</el-form-item>
<el-form-item >
<el-input v-model="form.pass" placeholder="密码"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">立即登陆</el-button>
<router-link :to="{path:'/user/reg'}"><el-button>注册</el-button></router-link>
</el-form-item>
</el-form>
</div>
</template>
<script>
//import router;
// import 其他vue组件的名称 from './LandingPage/其他vue组件的名称'
export default {
name: 'landing-page',
data(){
return{
form: {
name: '',
pass:'',
}
}
},
//导入其他的组件 components: { SystemInformation },
methods: {
onSubmit() {
this.$axios({
method: 'post',
url: '/api/user/qby/',
header:{
'Content-Type':'application/x-www-form-urlencoded' //如果写成contentType会报错
},
data:this.qs.stringify({name:this.form.name,pass:this.form.pass}),
}).then((res) => {
console.log(res);
if(res.data=="success"){
//跳转页面
alert("登陆成功");
}else{
// 不跳转
alert("用户名或密码错误");
}
});
},
}
}
</script>
<style>
/*
#app{
background-image: url('~@/assets/img/bg1.jpg');
}
*/
.img{
position: absolute;
width:100%;
height:40rem;
}
.mc{
padding-top: 110px;
padding-left: 552px;
width: 400px;
}
</style>
效果如下
给页面添加背景图片
图片放在assets文件夹下面img文件夹下面
写法是 <img src="~@/assets/img/bj1.jpg" />
用~@/表示
部署项目
1、把electron-vue项目进行打包
控制台输出npm run build
但是报错
安装electron-builder
yarn add electron-builder --dev
再次在控制台输入yarn run build
又报错了
解决方案
如果您使用的是 Babel,你将需要添加 syntax-dynamic-import 插件,才能使 Babel 可以正确地解析语法。
yarn add babel-plugin-syntax-dynamic-import
打开webpack.main.config.js里面修改以下的内容
{
test: /\.js$/,
loader:'babel-loader',
options:{
plugins:['syntax-dynamic-import']
},
},
把子路由的配置改成这样的;
import login from '@/components/user/login.vue'
import reg from '@/components/user/reg.vue'
export default[
{
path: '/',
name: 'login',
component:login,
},
{
path: '/user/reg',
name:'reg',
component:reg,
}
];
先运行项目,yarn run dev
如果正常就继续,如果不正常的话,报错 vue- Couldn't find preset "es2015" relative to directory
解决办法 yarn add babel-preset-es2015 --save-dev
再次运行项目 yarn run dev
失败的原因是下载的时间太长了导致的
electron-vue项目打包成桌面开发程序的流程
1、下载SHASUMS256.txt与electron-v2.0.18-win32-x64.zip
现在打开链接,然后再浏览器上下载,再放到缓存里面
https://npm.taobao.org/mirrors/electron/2.0.18/
记住SHASUMS256.txt 也要下载 可以新建一个txt文件,然后复制内容进去保存
将SHASUMS256.txt改成SHASUMS256.txt-2.0.18
不同的环境变量的项目所需要的版本不一样,你可以通过yarn run build ,当程序卡住的时候,仔细看一下提示,需要什么版本的;当然其他版本的不影响,你下载下来,只需要改文件夹的名称就可以了,但是你必须知道你的版本是什么。
下载winCodeSign-2.6.0(至于版本,你们可以yarn run build 到某个地方就会卡住,你们看看是提示是什么版本的)
https://github.com/electron-userland/electron-builder-binaries/releases/tag/winCodeSign-2.6.0
如果版本是2.7 就更改网页最后的版本号就可以了
下载结束以后,在Cache里面新建一个winCodeSign的文件夹,记住这个名字不能改
在这个winCodeSign文件夹里面新建一个winCodeSign-你的版本的名称,如果是2.6.0.7就去前面2个点.
拷贝刚才下载的文件里面的这几个东西
然后再yarn run build
如果发现又卡住下载东西,仔细看是什么,如果还是winCodeSign,说明你以上的配置不对!!!
仔细看文件名称以及版本号;
如果你下错了winCodeSign版本没有关系,一样可以用,里面内容一样的,要把文件夹名称改成你需要的就可以了!!
3、下载nsis
不同的环境变量的项目所需要的版本不一样,你可以通过yarn run build ,当程序卡住的时候,仔细看一下提示,需要什么版本的;当然其他版本的不影响,你下载下来,只需要改文件夹的名称就可以了,但是你必须知道你的版本是什么。
如果是nsis的话,就继续往下看
下载nsis-3.0.3.2
https://github.com/electron-userland/electron-builder-binaries/releases/tag/nsis-3.0.3.2
在Cache文件夹里面新建一个文件夹nsis
在文件夹nsis里面新建一个文件夹nsis-版本号
我需要的是nsis-3.0.4.1 ,但是不影响,因为虽然版本不一样,但是里面内容一样,文件夹名称与需要的一样就可以了
现在运行yarn run build 就没有问题了
在build文件夹里面有生成的.exe程序
把exe程序放在桌面上,关闭vscode
当打包结束以后,运行界面没有问题。但是axios请求报错!!!!
原因:proxy配置的跨域设置只适合开发环境,不适合上线的环境(以及打包的项目)
有两个方法可以解决这个问题
方法一、如果你是electron是v10.*.*版本的话,可以用这个方法
1.1、删除掉proxy代理,那个只是开发环境下面使用的跨域设置,没有用
1.2、打开main文件夹下面的index.js
找到mainWindow = new BrowserWindow({}) 添加跨域设置 webPreferences:{webSecurity:false}
mainWindow = new BrowserWindow({
height: 563,
useContentSize: true,
width: 1000,
//跨域设置
webPreferences:{webSecurity:false}
//跨域设置
})
再在下面添加
//跨域
app.commandLine.appendSwitch('disable-features', 'OutOfBlinkCors');
//跨域
在axios请求的方法里面把url改成绝对路径
this.$axios({
method: 'post',
url: 'http://185.92.156.173:8088/user/insert/',
header:{
'Content-Type':'application/x-www-form-urlencoded' //如果写成contentType会报错
},
data:this.qs.stringify({username:this.form.name,password:this.form.pass,tell:this.form.tell}),
}).then((res) => {
console.log(res)
});
然后保存,打包,就可以了
前提是你的electron是v10版本以上的,不然没用。
我亲自测试了,把这个exe程序放在其他没有这些环境变量的电脑上都可以,有效!(前提你的后端是能访问到的,云服务器)
方法二、nginx反向代理(最普遍的方法)
1、安装nginx
官网地址 http://nginx.org/download/nginx-1.0.11.zip
2、解压后,把文件放在想要的地方
打开文件夹,双击 nginx.exe,就是启动了;
但是我双击了以后闪退了,原因是80端口被占用了;
修改conf/nginx.conf文件中的 端口
我改成了8090 ,保存然后再双击试试看
是不是一闪而过,都看不到窗口,我就是的。
我改了好几次,但是还是一闪而退,百度了很多,不需要配置环境变量,不需要的;
后来,我打开了任务管理器,发现很多的nginx.exe在运行。我没有关闭
全部关闭以后,在双击(即使还是一闪而过,别怕),在页面上输入localhost:8085(你在配置文件里面设置的端口号),我改了很多,最后是8085端口
居然能打开,没问题,我都崩溃了.............我还以为跟tomcat一样呢?
经过几个小时的尝试,告诉大家一个很重要的技巧
1、想要知道nginx服务有没有开启,打开任务管理器
有两个nginx是对的;想要关闭的话,可以直接点击关闭进程,两个
用谷歌浏览器,我用了火狐浏览器,很快的修改配置参数,火狐浏览器都反应不过来,我都不知道究竟是对是错
打开ngnix的nginx.conf配置文件
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream domi{
server 182.96.153.143:8088;
}
server {
listen 8085;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
location /ttt/ {
proxy_pass http://domi/;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
要点:
1、申明另一个服务器的地址以及端口
upstream domi{
server 182.92.153.173:8088;
}
并且 不能有_ 可以是domi 可以是yyy 不能是e_p
2、proxy_pass 里面要与这个申明的服务器名称一致
3、先访问ngnix是否没问题 比如ngnix的地址是http://localhost:8085
那么在后面网址加上ttt就可以了
4、然后再electron-vue项目里面,axios请求的地址设置为http://ngnix的访问地址/ttt
若在本机电脑上:http://localhost:8085/ttt/
若后端服务器与ngnix在阿里云上:http://阿里云地址:8085/ttt/
不管你在哪里,记住,你的(ngnix的地址:端口号)/ttt/
当然,如果采用ngnix反向代理跨域,就可以注释掉方法一的配置
然后再进行yarn run build就可以了
我试过了可以注册登录
您的支持是我分享经验的动力