前后端分离+部署到阿里云

前后端分离小demo + 部署到阿里云

前言

  • 前端 Vue CLI 组件化开发,所需插件 vuex、axios、router
  • 后端 Spring Boot 工程

核心:前端80访问后端9000,后端访问数据库3306

小demo 功能简介:有导航栏可以切换,首页和关于页面是默认有的,备忘录是我新增的,备忘录页面的数据来自后端,后端访问数据库获得的,可以新增备忘录数据,可以删除备忘录中的数据,与后端数据库进行数据交互。
在这里插入图片描述

前端编写

1、新建一个 vue 工程,安装所需插件

vue create 项目名 
cd 项目名 # 进到工程目录
vue add axios
vue add router
vue add vuex
npm run serve # 启动

工程结构:
在这里插入图片描述
2、用 VSCode 打开 vue 工程进行编辑,由于我想用 Bootstrap,所以需要修改一下 public 目录下的 index.html,那么 App.vue 中的 style 就可去掉不用

<!doctype html>
<html lang="zh">

<head>
    <title>Vue CLI 单页面程序</title>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">

</head>

<body>

    <!-- 挂载点 -->
    <div id="app"></div>

</body>

</html>

3、App.vue - 起始视图
加上面包屑导航,切换的视图都是挂载在 router-view 标签的位置

<template>
  <div id="app">

    <!-- 可组件化,导航栏 -->
    <nav class="breadcrumb">
      <a class="breadcrumb-item" href="/">首页</a>
      <a class="breadcrumb-item" href="/todos">备忘录</a>
      <a class="breadcrumb-item" href="/about">关于</a>
    </nav>

    <div class="container">
      <div class="row">
        
        <div class="col-lg-9">

            <!-- 路由视图 挂载点,可以有多个 -->
            <router-view/>
        
        </div>

      </div>
    </div>
  
  </div>
</template>

<script>

export default {
  name: 'app',
  components: {
  }
}
</script>

4、在 views 目录下多定义一个备忘录视图 Todos.vue,其中输入框和列表是单独的组件,这样模块化程度高,以后可复用

<!--.vue 快速生成模板-->
<template>
    <div class="container">
        <!-- 巨幕 -->
        <div class="jumbotron jumbotron-fluid">
            <div class="container">
                <h1 class="display-3">{{$store.state.todosTitle}}</h1>
                <p class="lead">{{title}}</p>
            </div>
        </div>
        <!-- 输入框 -->
        <n-task/>
        <!-- 列表 -->
        <n-list/>

    </div>
</template>

<script>
// 1.导入组件
import NTask from '@/components/Todos/NTask.vue'
import NList from '@/components/Todos/NList.vue'


export default {
    components:{
    	// 2.注册组件
        NTask,
        NList
    },
    data() {
        return {
            title:'组件内的数据'
        }
    }
    
}
</script>

<style>

</style>

5、Todos.vue 用到了组件 NList.vueNTask.vue,在 components 目录下新建
在这里插入图片描述
NList.vue

<template>
  <div class="list-group">
      <a href="#" 
            v-for="(item,index) in $store.state.todoList" :key="index"
            class="list-group-item list-group-item-action">{{item.task}}
            <button 
              @click="remove(item.id)"
              type="button" 
              class="btn btn-outline-danger btn-sm float-right">X</button>
      </a>
  </div>
</template>

<script>
export default {
    methods:{
      remove:function(id){
        //1、直接访问了 Vuex.Store 中的状态
        //this.$store.state.todoList.splice(index,1);
        
        //2、最佳实践:调用 action
        this.$store.dispatch('deleteTask', id);

      }
    },
    // 使用vuex的组件中进行分发
    // 获取后端的数据
    mounted(){
      this.$store.dispatch('getList')
    }
}
</script>

<style>

</style>

NTask.vue

<template>
    <div class="form-group">
      <input 
        @keyup.enter="create()"
        v-model="task"
        type="text"
        class="form-control form-control-lg" 
        placeholder="今日事今日毕">
    </div>
</template>

<script>
export default {
  data() {
    return {
      task:''
    }
  },
  methods:{
    create:function(){
      // 1、直接访问了 Vuex.Store 中的状态
      //this.$store.state.todoList.unshift(this.task);
      
      // 2、最佳实践:调用 action
      this.$store.dispatch('createTask', this.task);
		
      this.task='';
    },
  }
}
</script>

<style>

</style>

6、路由 router 目录下的 index.js ,定义路由规则

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
// 导入
import Todos from '@/views/Todos.vue'

Vue.use(VueRouter)

const routes = [
    {
        path: '/',
        name: 'Home',
        component: Home
    },
    {
        path: '/todos',
        component: Todos
    },
    {
        path: '/about',
        name: 'About',
        // route level code-splitting
        // this generates a separate chunk (about.[hash].js) for this route
        // which is lazy-loaded when the route is visited.
        component: () =>
            import ( /* webpackChunkName: "about" */ '../views/About.vue')
    }
]

const router = new VueRouter({
    mode: 'history',
    base: process.env.BASE_URL,
    routes
})

export default router

7、仓库 store 目录下的 index.js,我的后端接口是9000

import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'

// 使用仓库
Vue.use(Vuex)

// 集中式状态管理
// 全局唯一,单例
// 状态自管理应用
export default new Vuex.Store({
    // 驱动应用的数据源
    state: {
        url: 'http://阿里云公网ip:9000/todo',
        todosTitle: '备忘录($store.state)',
        todoList: [],
    },
    // 改变 state 中的状态
    mutations: {
        getList(state, list) {
            state.todoList = list;
        }
    },
    // 响应在view上的用户输入导致的状态变化
    // action 提交的是 mutation,而不是直接变更状态
    actions: {
        // 新增任务
        createTask({ dispatch }, task) {
            let params = {
                    task: task
                }
            axios.post(this.state.url, params)
                .then(res => {
                    console.log(res.status)
                    if (200 == res.status) {
                    	// 重新加载数据列表
                        dispatch('getList');
                    }
                })
                .catch(err => {
                    console.error(err);
                })
        },
        // 删除任务
        deleteTask({ dispatch }, id) {
            let url = this.state.url + "/" + id;
            axios.delete(url)
                .then(res => {
                    console.log(res.status, id);
                    if (200 == res.status) {
                        dispatch('getList');
                    }
                })
                .catch(err => {
                    console.error(err);
                })
        },
        // 从后端获取数据
        // 获取任务列表
        getList(context) {
            let url = this.state.url;
            axios.get(url)
                .then(res => {
                    console.log(res.data);
                    context.commit("getList", res.data);
                })
                .catch(err => {
                    console.error(err);
                })
        }
    },
    getters: {},
    modules: {},
})

8、打包 vue 工程
先停止运行 vue 工程

ctrl + c

再编译打包,打包之后可在工程目录中的 dist 目录查看

npm run build

在这里插入图片描述

后端编写

1、entity

public class Todo {

	int id;
	
	String task;

	public Todo() {
		
	}
	
	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getTask() {
		return task;
	}

	public void setTask(String task) {
		this.task = task;
	}

	@Override
	public String toString() {
		return "Todo [id=" + id + ", task=" + task + "]";
	}
	
}

2、mapper

@Mapper
public interface TodoMapper {

	@Insert("insert into todo(task) value(#{task})")
	@Options(useGeneratedKeys = true,keyColumn = "id",keyProperty = "id")
	void insert(Todo todo);
	
	@Delete("delete from todo where id=#{id}")
	void deleteById(int id);
	
	@Select("select id,task from todo")
	Todo[] selectAll();
}

3、controller

@RestController
@CrossOrigin
@RequestMapping("/todo")
public class TodoController {

	@Autowired
	TodoMapper mapper;
	
	@SuppressWarnings({ "rawtypes", "unchecked" })
	@GetMapping
	public ResponseEntity getTodo() {
		Todo[] todoList = mapper.selectAll();
		return new ResponseEntity(todoList, HttpStatus.OK);
	}
	
	@PostMapping
	public void createTask(@RequestBody Todo todo) {
		mapper.insert(todo);
	}
	
	@DeleteMapping("/{id}")
	public void deleteTask(@PathVariable int id) {
		mapper.deleteById(id);
	}
	
}

4、配置文件
在这里插入图片描述
5、打成 jar 包,Maven install,完成之后在工程目录的 targer 文件夹下
在这里插入图片描述
在这里插入图片描述

数据库

1、新建数据库 todos,新建一张表 todo:
在这里插入图片描述
表结构:
在这里插入图片描述
随便放几条数据测试一下
在这里插入图片描述
2、导出数据库脚本 Data Export
在这里插入图片描述

部署到阿里云

1、上传 sql 脚本 到 阿里云服务器 /opt 目录下
命令:scp sql脚本的路径 root@阿里云公网IP:/opt

2、上传 后端打包好的 jar 包 到 阿里云服务器 /opt 目录下
命令:scp jar包的路径 root@阿里云公网IP:/opt
在这里插入图片描述
3、上传 前端编译好的 dist 到 阿里云服务器 /opt 目录下,由于 dist 是目录,需要递归 -r
命令:scp -r dist的路径 root@阿里云公网IP:/opt
在这里插入图片描述
4、ssh 安全登录阿里云服务器
命令:ssh root@阿里云公网IP,随后输入登录密码即可
登录之后安装所需软件:

apt update # 更新包列表
apt upgrade # 系统更新
apt install nginx # 安装 nginx
apt install mysql-server # 安装 mysql 服务
java # 按照提示语句安装相应版本的 java,apt install.....

5、配置 mysql

mysql -uroot -p # 第一次不用密码,直接回车两次即可
update user set host='%' where user='root'; # 更新 user 的 host 字段为 %
FLUSH PRIVILEGES; # 刷新一下
alter user 'root'@'%' IDENTIFIED WITH caching_sha2_password BY '你的密码'; # 设置密码
exit # 退回 服务器终端

修改mysql配置文件,去到 /etc/mysql/mysql.conf.d 目录下,编辑 mysqld.conf 文件

cd /etc/mysql/mysql.conf.d 
nano /mysqld.conf

修改配置文件中的一句:bind_address=0.0.0.0,保存后退出即可
重启一下 mysql :service mysql restart

6、导入数据库

mysql -uroot -p
create database todos;
source /opt/todo.sql # 执行刚上传到 /opt 的sql脚本

7、修改 nginx 的配置

cd /opt
mv dist www # 刚上传的前端的dist文件夹,重命名为 www,更符合规范
cd /etc/nginx 
cp nginx.conf nginx.cong.old # 修改前,先备份一下,以免出错

配置文件中加入黄色框那一段,保存后退出
在这里插入图片描述
8、启动 java 程序

cd /opt
mv todo-0.0.1-SNAPSHOT.jar todo.jar # 名字太长,重命名一下
chmod +x todo.jar # 修改权限,可执行
nohup java -jar todo.jar & # 运行,不挂起,关闭终端程序也可继续运行
ps -aux | grep java # 查看进程号
kill 进程号 # 杀死进程可终止程序运行

最终效果

通过 阿里云公网IP 访问,点击导航栏3个页面可来回切换
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
终…

  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值