①创建一台opencloud8的腾讯云服务器
②用xshell连接服务器
③vue中新建.env.development配置文件
.env.development:
VUE_APP_BASEURL='http://localhost:9090'
.env.production:
VUE_APP_BASEURL='http://服务器ip:9090'
④修改main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import request from "@/utils/request";
Vue.config.productionTip = false
Vue.use(ElementUI,{size:'small'});
Vue.prototype.$request=request //引入request
Vue.prototype.$baseUrl=process.env.VUE_APP_BASEURL
new Vue({
router,
render: h => h(App)
}).$mount('#app')
⑤修改request.js:
request:
import axios from 'axios'
import router from "@/router";
// 创建可一个新的axios对象
const request = axios.create({
baseURL: process.env.VUE_APP_BASEURL, // 后端的接口地址 ip:port
timeout: 30000
})
// request 拦截器
// 可以自请求发送前对请求做一些处理
// 比如统一加token,对请求参数统一加密
request.interceptors.request.use(config => {
config.headers['Content-Type'] = 'application/json;charset=utf-8';
let user=JSON.parse(localStorage.getItem("honey-user")||'{}')
// let user = localStorage.getItem("user") ? JSON.parse(localStorage.getItem("user")) : null
config.headers['token'] = user.token // 设置请求头
return config
}, error => {
console.error('request error: ' + error) // for debug
return Promise.reject(error)
});
// response 拦截器
// 可以在接口响应后统一处理结果
request.interceptors.response.use(
response => {
let res = response.data;
// 兼容服务端返回的字符串数据
if (typeof res === 'string') {
res = res ? JSON.parse(res) : res
}
if(res.code === '401'){
router.push('/login')
}
return res;
},
error => {
console.error('response error: ' + error) // for debug
return Promise.reject(error)
}
)
export default request
⑤修改User页
User:
<template>
<div>
<div>
<el-input style="width: 200px" placeholder="查询用户名" v-model="username"></el-input>
<el-input style="width: 200px;margin: 0 10px" placeholder="查询姓名" v-model="name"></el-input>
<el-button type="primary" @click="load(1)">查询</el-button>
<el-button type="info" @click="reset">重置</el-button>
</div>
<div style="margin: 10px 0">
<el-button type="primary" @click="handleAdd">新增</el-button>
<el-button type="danger" @click="delbatch">批量删除</el-button>
<el-button type="info" @click="exportData" plain>批量导出</el-button>
<el-upload :action="$baseUrl+'/user/import'" :headers="{token:user.token}" style="display: inline-block;margin-left: 10px" :show-file-list="false" :on-success="handleImport">
<el-button type="primary" plain>批量导入</el-button>
</el-upload>
</div>
<el-table @selection-change="handleSelectionChange" :data="tableData" stripe :header-cell-style="{backgroundColor:'aliceblue',color:'#666'} ">
<el-table-column type="selection" width="55" align="center">
</el-table-column>
<el-table-column prop="id" label="ID" width="70"></el-table-column>
<el-table-column prop="username" label="用户名"></el-table-column>
<el-table-column prop="name" label="姓名"></el-table-column>
<el-table-column prop="phone" label="手机号"></el-table-column>
<el-table-column prop="email" label="邮箱"></el-table-column>
<el-table-column prop="address" label="地址"></el-table-column>
<el-table-column label="头像">
<template v-slot="scope">
<div style="display: flex;align-items: center">
<el-image style="width: 50px;height: 50px;border-radius: 50%" v-if="scope.row.avatar" :src="scope.row.avatar" :preview-src-list="[scope.row.avatar]"></el-image>
</div>
</template>
</el-table-column>
<el-table-column prop="role" label="角色"></el-table-column>
<el-table-column label="操作" align="center" width="180">
<template v-slot="scope">
<div style="display: flex">
<el-button type="primary" plain size="mini" @click="handleEdit(scope.row)">编辑</el-button>
<el-button type="danger" plain size="mini" @click="del(scope.row.id)">删除</el-button>
</div>
</template>
</el-table-column>
</el-table>
<div class="block" style="margin: 10px 0">
<el-pagination
@current-change="handleCurrentChange"
:current-page="pageNum"
:page-sizes="[100, 200, 300, 400]"
:page-size="pageSize"
layout="total, prev, pager, next"
:total="total">
</el-pagination>
</div>
<el-dialog title="收货地址" :visible.sync="formVisible" width="30%">
<el-form :model="form" label-width="80px" style="padding-right: 20px" :rules="rules" ref="formRef">
<el-form-item label="用户名" prop="username">
<el-input v-model="form.username" ></el-input>
</el-form-item>
<el-form-item label="姓名" prop="name">
<el-input v-model="form.name"></el-input>
</el-form-item>
<el-form-item label="电话" prop="phone">
<el-input v-model="form.phone"></el-input>
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email"></el-input>
</el-form-item>
<el-form-item label="地址" prop="address">
<el-input type="textarea" v-model="form.address"></el-input>
</el-form-item>
<el-form-item label="角色" prop="role">
<el-radio-group v-model="form.role">
<el-radio label="管理员"></el-radio>
<el-radio label="用户"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="头像">
<el-upload
class="avatar-uploader"
:action="$baseUrl+'/file/upload'"
:headers="{ token: user.token }"
:file-list="form.avatar?[form.avatar]:[]"
list-type="picture"
:on-success="handleAvatarSuccess">
<el-button type="primary">上传头像</el-button>
</el-upload>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="save">确 定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
export default {
name:'User',
data(){
return{
tableData:[],
pageNum:1,
pageSize:5,
username:'',
name:'',
total:0,
formVisible:false,
form:{},
user:JSON.parse(localStorage.getItem('honey-user'||'{}')),
rules:{
username:[{
required:true,
message:'请输入用户名',
trigger:'blur'
}]
},
ids:[]
}
},
created() {
this.load()
},
methods:{
handleImport(res,file,fileList){
if(res.code==='200'){
this.$message.success("操作成功")
this.load(1)
}else{
this.$message.error(res.msg)
}
},
exportData(){
if(!this.ids.length){
window.open(this.$baseUrl+"/user/export?token="+this.user.token+"&username="+this.username+"&name="+this.name)
}else{
let idStr=this.ids.join(',')
window.open(this.$baseUrl+"/user/export?token="+this.user.token+"&ids="+idStr)
}
},
delbatch(){
if(!this.ids.length){
this.$message.warning("请选择数据")
return
}
this.$confirm('您确认删除吗','确认删除',{type:'warning'}).then(response=>{
this.$request.delete('/user/delete/batch',{data:this.ids}).then(res=>{
if(res.code === '200'){
this.$message.success('操作成功')
this.load(1)
}else{
this.$message.error(res.msg)
}
})
}).catch(()=>{})
},
handleSelectionChange(rows){
this.ids=rows.map(v=>v.id)
},
del(id){
this.$confirm('您确认删除吗','确认删除',{type:'warning'}).then(response=>{
this.$request.delete('/user/delete/'+id).then(res=>{
if(res.code === '200'){
this.$message.success('操作成功')
this.load(1)
}else{
this.$message.error(res.msg)
}
})
}).catch(()=>{})
},
handleEdit(row){
this.form=JSON.parse(JSON.stringify(row))
this.formVisible=true
},
handleAdd(){
this.form={role:'用户'}
this.formVisible=true
},
save(){
this.$refs.formRef.validate((valid)=>{
if(valid){
this.$request({
url:this.form.id? '/user/update' : '/user/add',
method:this.form.id? 'PUT' : 'POST',
data:this.form
}).then(res=>{
if(res.code === '200'){
this.$message.success('保存成功')
this.load(1)
this.formVisible=false
}else{
this.$message.error(res.msg)
}
})
}
})
},
handleAvatarSuccess(response,file,fileList){
console.log(response)
this.form.avatar=response.data
},
reset(){
this.name=''
this.username=''
this.load()
},
load(pageNum){
if(pageNum){
this.pageNum=pageNum
}
this.$request.get('/user/selectByPage',{
params:{
pageNum:this.pageNum,
pageSize:this.pageSize,
username:this.username,
name:this.name
}
}).then(res=>{
this.tableData=res.data.records
this.total=res.data.total
})
},
handleCurrentChange(pageNum){
this.load(pageNum)
},
}
}
</script>
<style scoped>
</style>
⑥修改Person页
Person:
<template>
<div>
<el-card style="width: 50%">
<el-form :model="user" label-width="80px" style="padding-right: 20px">
<div style="margin: 15px;text-align: center">
<el-upload
class="avatar-uploader"
:action="$baseUrl+'/file/upload'"
:headers="{ token: user.token }"
:show-file-list="false"
:on-success="handleAvatarSuccess">
<img v-if="user.avatar" :src="user.avatar" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
</div>
<el-form-item label="用户名" prop="username">
<el-input v-model="user.username" disabled></el-input>
</el-form-item>
<el-form-item label="姓名" prop="name">
<el-input v-model="user.name"></el-input>
</el-form-item>
<el-form-item label="电话" prop="phone">
<el-input v-model="user.phone"></el-input>
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="user.email"></el-input>
</el-form-item>
<el-form-item label="地址" prop="address">
<el-input type="textarea" v-model="user.address"></el-input>
</el-form-item>
</el-form>
<div style="text-align: center;margin-bottom: 20px"><el-button type="primary" @click="update">保存</el-button></div>
</el-card>
</div>
</template>
<script>
export default {
data(){
return{
user:JSON.parse(localStorage.getItem('honey-user'||'{}'))
}
},
methods:{
update(){
this.$request.put('/user/update',this.user).then(res=>{
if(res.code==='200'){
this.$message.success('保存成功')
localStorage.setItem('honey-user',JSON.stringify(this.user))
this.$emit('update:user',this.user)
}else{
this.$message.error(res.msg)
}
})
},
handleAvatarSuccess(response,file,fileList){
console.log(response)
this.user.avatar=response.data
}
}
}
</script>
<style scoped>
/deep/.el-form-item__label{
font-weight: bold;
}
/deep/.el-upload{
border-radius: 50%;
}
/deep/.avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
cursor: pointer;
position: relative;
overflow: hidden;
border-radius: 50%;
}
/deep/.avatar-uploader .el-upload:hover {
border-color: #409EFF;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
line-height: 178px;
text-align: center;
border-radius: 50%;
}
.avatar {
width: 178px;
height: 178px;
display: block;
border-radius: 50%;
}
</style>
⑦打包vue文件
在终端进入vue的文件夹进行打包:
npm run build
生成dist文件夹说明打包成功:
⑧打包springboot文件
生成target文件夹:
⑨上传打包文件并部署服务器java和mysql环境
在xshell中打开xftp:
创建目录下的各种文件夹:
将jar包和application.yml拖入java文件夹;
修改application.yml:
server:
port: 9090
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://${ip}:3306/honey2024?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2b8
username: root
password: 123456
servlet:
multipart:
max-file-size: 20MB
max-request-size: 20MB
ip: 服务器ip
在java目录下编辑启动脚本:vi start.vh
NAME=springboot-0.0.1-SNAPSHOT.jar
nohup java -jar $NAME > server.log 2>&1 &
echo 'start success'
编辑终止脚本:vi stop.sh
PORT=9090
pid=`netstat -tnlp | grep $PORT | grep -v grep | awk '{print $7}' | awk -F/ '{print $1}'`
if [ ${pid} ]; then
kill -9 $pid
echo "kill $PORT"
else
echo 'stop sucess!'
fi
赋予java文件夹下读写权限:chmod +x *
dist拖入vue文件夹;
下载环境文件并上传至服务器的tmp文件夹下:
链接:https://pan.baidu.com/s/1H5WqBiq0iKACDnh1uBlAZA?pwd=anb8
提取码:anb8
安装jdk1.8:
tar -zxvf /tmp/jdk-8u371-linux-x64.tar.gz -C /usr/local/
mv /usr/local/jdk1.8.0_371 /usr/local/java
vi /etc/profile
export JAVA_HOME=/usr/local/java
export PATH=$JAVA_HOME/bin:$PATH
source /etc/profile
# 验证
java -version
安装 nginx:
#安装gcc
yum install gcc-c++
#安装PCRE pcre-devel
yum install -y pcre pcre-devel
#安装zlib
yum install -y zlib zlib-devel
#安装Open SSL
yum install -y openssl openssl-devel
解压、编译 nginx 并安装:
mkdir /usr/local/nginx
tar -zxvf /tmp/nginx-1.24.0.tar.gz -C /usr/local/nginx
cd /usr/local/nginx/nginx-1.24.0
# 编译安装
./configure --with-http_stub_status_module --with-http_ssl_module
make && make install
nginx 命令:
cd /usr/local/nginx/sbin
./nginx # 启动
ps -ef | grep nginx # 查看
./nginx -s stop # 停止
./nginx -s reload # 重启
nginx 配置:
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root /home/server/honey2024/vue/dist;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
}
在 Manager 的 mouted 函数里加上这个判断即可 防止用户在未登录的情况下进入首页:
mounted() { // 页面加载完成之后触发
if (!this.user.id) { // 当前的浏览器没有用户信息
this.$router.push('/login')
}
},
安装mysql:
rpm -qa | grep mariadb
yum remove -y mariadb-connector-c-3.1.11-2.oc8.1.x86_64
yum remove -y mariadb-connector-c-config-3.1.11-2.oc8.1.noarch
下载 mysql 并 上传到 /tmp 目录
安装 mysql 命令:
mkdir /data/mysql
tar -zxvf /tmp/mysql-5.7.42-el7-x86_64.tar.gz -C /usr/local
mv /usr/local/mysql-5.7.42-el7-x86_64 /usr/local/mysql
# 添加用户组
groupadd mysql
useradd -r -g mysql mysql
chown -R mysql.mysql /usr/local/mysql
chown -R mysql.mysql /data/mysql
cd /usr/local/mysql
/usr/local/mysql/bin/mysqld --user=mysql --basedir=/usr/local/mysql/ --datadir=/data/mysql --initialize
# 将mysql加入到服务中
cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysql
# mysql快捷方式
ln -s /usr/local/mysql/bin/mysql /usr/bin
ln -s /usr/lib64/libtinfo.so.6.1 /usr/lib64/libtinfo.so.5
ln -s /usr/lib64/libncurses.so.6.1 /usr/lib64/libncurses.so.5
临时密码:STsrIurl7D>8
配置 mysql 配置文件 my.cnf
vi /etc/my.cnf
[mysqld]
datadir=/data/mysql
basedir=/usr/local/mysql
socket=/tmp/mysql.sock
user=mysql
port=3306
character-set-server=utf8
# 取消密码验证
# skip-grant-tables
# # Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
启动 mysql: **service mysql start **
开机启动: **chkconfig mysql on **
登录 mysql: **mysql -uroot -p **
输入临时密码进入 mysql
修改密码并设置权限:
SET PASSWORD = PASSWORD('123456');
use mysql;
update user set host ='%'where user ='root' and host ='localhost';
flush privileges;
exit;
服务器开放3306端口用navicat连接数据库:
新建数据库:
将本地honey2024的user表拖入服务器的honey2024进行复制:一路点下一步
修改pom.xml对应部分:重新生成jar包上传
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<configuration>
<mainClass>com.example.springboot.SpringbootApplication</mainClass>
<includeSystemScope>true</includeSystemScope>
</configuration>
<executions>
<execution>
<phase>package</phase>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
进入/home/server/honey2024/java运行start.sh脚本:
查看是否生效:tail -100f server.log,如图说明成功(此时还需要在服务器开放9090端口,不要忘了)
此时前后端都部署完成,网站上线成功