首页 > 其他分享 >前后端分离但人不分离:IDEA+VUE创建springboot项目和对应的前端项目

前后端分离但人不分离:IDEA+VUE创建springboot项目和对应的前端项目

时间:2024-08-15 11:49:55浏览次数:7  
标签:VUE console err url res 分离 IDEA import data

参考链接:

环境要求:

  • 安装IDEA
  • 安装mysql、Navicat
  • 配置好maven
  • 安装vue-cli
  • 安装postman

 思想:

  • 用IDEA创建springboot项目,并同时勾选依赖 springboot web, mysql, mybatics, lombok
  • 设置连接数据库,写一个测试接口 hello,用浏览器测试成功后开始写对数据库的crud接口
  • 在后端测试成功后,写前端项目,在前端项目中用axios访问get、post请求,并返回结果
  • 在前端测试成功后,打包前端项目,并把打包后的dist文件夹中的内容放到idea项目的 src/main/resources/static 目录下
  • idea服务器重启,即可用后端的地址正常访问。
  • 因为图片太多,所以展示时选择了缩小,看不清可以 右键 | 在新标签页打开图片

一、查看要操作的数据库

user表

选中表user,右键“设计表”可以看到属性类型

 二、用idea创建springboot项目

File | New | Project 

 Next

 Create,等待项目下载完成

项目下载完成后,目录如下。关掉无关页面,双击打开 pom.xml。如果有忘记安装的依赖可以在这里写入,然后刷新maven安装。

 打开 application.properties 默认内容如下

  添加连接数据库的配置

spring.application.name=mydemo
server.port=8081

spring.datasource.url=jdbc:mysql://localhost:3306/test_springboot?useSSL=false&useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=1234
spring.datasource.driverClassName = com.mysql.cj.jdbc.Driver

开始写后端代码:在com.example.mydemo 下新建3个包 controller、mapper、entity

然后 entity 中新建一个 User类,按照数据库user表的列属性声明变量,并引入 @Data 注解

import lombok.Data;

@Data
public class User {
    private int id;
    private String name;
    private int age;
    private int grade;
}

在mapper中新建 UserMapper 接口(暂时先不写内容)

 在 controller 中新建 UserController.java, 并写一个测试接口

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {
    @GetMapping("/hello")
    public String hello() {
        return "HELLO";
    }
}

双击 MydemoApplication.java 打开,右键 Run,启动服务器

 在浏览器地址栏输入 http://localhost:8081/hello ,页面显示 HELLO 表示正确。

 三、写对数据库操作的接口

先在 MydemoApplication.java 上加注解扫描mapper类

@MapperScan("com.example.mydemo.mapper")

 然后在 UserMapper.java 中编写第一个查询接口

import com.example.mydemo.entity.User;
import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface UserMapper {
    @Select("select * from user")
    List<User> queryAll();
}

在UserController.java中调用 queryAll 并添加对应注解

import com.example.mydemo.mapper.UserMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequiredArgsConstructor
public class UserController {
    private final UserMapper userMapper;

    @GetMapping("/hello")
    public String hello() {
        return "HELLO";
    }

    @GetMapping("/findAll")
    public List<User> findAllUser() {
        return userMapper.queryAll();
    }
}

 重启服务器,在浏览器输入 http://localhost:8081/findAll  (注意大小写)就查到了数据,和数据库表中的数据一样。

 四、在vue项目中调用 http://localhost:8081/findAll 接口

 新建一个vue2项目,npm run serve 运行

安装 axios 详细过程可以参考 https://www.cnblogs.com/sunshine233/p/18334975

然后在HelloWorld.vue 中删除无用的代码,写布局和axios访问接口 

<template>
  <div class="hello">
    <h2>测试和 springboot 项目配合使用接口</h2>
  </div>
</template>

<script>
import axios from "axios";

export default {
  name: 'HelloWorld',
  data() {
    return {
      baseUrl: "http://localhost:8081"
    }
  },
  mounted() {
    this.testHello();
  },
  methods: {
    testHello() {
      const url = this.baseUrl + "/hello";
      axios.get(url).then(res => {
        console.log('res', res.data);
      }).catch(err => {
        console.log('err', err);
      })
    }
  }
}
</script>

<style scoped></style>

 但是运行后发现报错 has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.  

这是因为跨域了。跨域有很多种解决办法,这里我使用最简单的一种:后端代码controller类上加注解  @CrossOrigin   然后重启服务器。

 刷新前端页面,没有报错并返回 HELLO

 然后在前端页面中调用 /findAll 接口,成功返回数据。

  /**
     * 访问"查询所有信息"接口
     * 成功返回 所有信息json
     */
    testGetAllRecords() {
      const url = this.baseUrl + "/findAll";
      axios.get(url).then(res => {
        console.log('res.data', res.data);
      }).catch(err => {
        console.log('err', err);
      })
    }

 

 五、编写、测试post接口

在mapper中编写插入、修改接口

package com.example.mydemo.mapper;

import com.example.mydemo.entity.User;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

public interface UserMapper {
    @Select("select * from user")
    List<User> queryAll();

    @Update("insert into user(name, age,grade) values(#{name}, #{age}, #{grade})")
    @Transactional
    void insertRecord(User user);

    @Update("update user set name=#{name}, age=#{age}, grade=#{grade} where id=#{id}")
    @Transactional
    void updateRecordById(User user);
}

 在controller中调用mapper接口

package com.example.mydemo.controller;

import com.example.mydemo.entity.User;
import com.example.mydemo.mapper.UserMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@CrossOrigin
@RestController
@RequiredArgsConstructor
public class UserController {
    private final UserMapper userMapper;

    @GetMapping("/hello")
    public String hello() {
        return "HELLO";
    }

    @GetMapping("/findAll")
    public List<User> findAllUser() {
        return userMapper.queryAll();
    }
    
    @PostMapping("/insertRecord")
    public String insertUser(@RequestBody User user) {
        userMapper.insertRecord(user);
        return "插入数据成功!";
    }

    @PostMapping("/updateRecord")
    public String updateUser(@RequestBody User user) {
        userMapper.updateRecordById(user);
        return "更新数据成功!";
    }
}

 重启服务器。因为浏览器不能模拟post请求,所以需要用postman进行post请求。

注意body类型,数据插入成功。

 然后在前端测试插入数据。

    /**
     * 访问"插入数据"接口
     * 成功返回 “插入数据成功!”
     */
    testPostInsertRecord() {
      const url = this.baseUrl + "/insertRecord";
      const newRecord = {
        "name": "dannis",
        "age": 33,
        "grade": 54
      };

      axios({
        url: url,
        method: 'post',
        "content-type": "application/x-www-form-urlencoded",
        data: newRecord
      }).then((res) => {
        console.log("res.data:", res.data);
      }).catch((err) => {
        console.log("err:", err);
      });
    },

 运行后插入成功。

刷新数据库又多了一条新数据

 但此时插入的数据是写死的,为了能插入动态的数据,我们需要再前端页面增加输入框。

<template>
  <div class="hello">
    <h2>测试和 springboot 项目配合使用接口</h2>
    <div>
      <div class="input-box">
        <p>name:</p>
        <input v-model="userInfo.name" />
        <br>
        <p>age:</p>
        <input v-model="userInfo.age" />
        <br>
        <p>grade:</p>
        <input v-model="userInfo.grade" />
      </div>
      <button @click="testPostInsertRecord">插入数据</button>
    </div>
  </div>
</template>

<script>
import axios from "axios";

export default {
  name: 'HelloWorld',
  data() {
    return {
      baseUrl: "http://localhost:8081",
      userInfo: {
        name: "",
        age: null,
        grade: null
      }
    }
  },
  mounted() {
    // this.testPostInsertRecord();
  },
  methods: {
    /**
     * 访问测试接口
     * 成功返回 HELLO
     */
    testHello() {
      const url = this.baseUrl + "/hello";
      axios.get(url).then(res => {
        console.log('res.data', res.data);
      }).catch(err => {
        console.log('err', err);
      })
    },
    /**
     * 访问"查询所有信息"接口
     * 成功返回 所有信息json
     */
    testGetAllRecords() {
      const url = this.baseUrl + "/findAll";
      axios.get(url).then(res => {
        console.log('res.data', res.data);
      }).catch(err => {
        console.log('err', err);
      })
    },
    /**
     * 访问"插入数据"接口
     * 成功返回 “插入数据成功!”
     */
    testPostInsertRecord() {
      const url = this.baseUrl + "/insertRecord";
      // const newRecord = {
      //   "name": "dannis",
      //   "age": 33,
      //   "grade": 54
      // };

      axios({
        url: url,
        method: 'post',
        "content-type": "application/x-www-form-urlencoded",
        data: this.userInfo
      }).then((res) => {
        console.log("res.data:", res.data);
      }).catch((err) => {
        console.log("err:", err);
      });
    },
  }
}
</script>

<style scoped>
.input-box p {
  display: inline-block;
  width: 60px;
}
</style>

  插入数据成功

 为了方便查看,在前端把查到的所有用户信息显示出来。

<template>
  <div class="hello">
    <h2>测试和 springboot 项目配合使用接口</h2>
    <div class="input-box">
      <p>name:</p>
      <input v-model="userInfo.name" />
      <br>
      <p>age:</p>
      <input v-model="userInfo.age" />
      <br>
      <p>grade:</p>
      <input v-model="userInfo.grade" />
    </div>
    <button @click="testPostInsertRecord">插入数据</button>

    <table cellspacing="10">
      <tr>
        <th>id</th>
        <th>name</th>
        <th>age</th>
        <th>grade</th>
      </tr>
      <tr v-for="record in allRecords" :key="record.id">
        <td>{{ record.id }}</td>
        <td>{{ record.name }}</td>
        <td>{{ record.age }}</td>
        <td>{{ record.grade }}</td>
      </tr>
    </table>
  </div>
</template>

<script>
import axios from "axios";

export default {
  name: 'HelloWorld',
  data() {
    return {
      baseUrl: "http://localhost:8081",
      allRecords: [],
      userInfo: {
        name: "",
        age: null,
        grade: null
      }
    }
  },
  mounted() {
    this.testGetAllRecords();
  },
  methods: {
    /**
     * 访问测试接口
     * 成功返回 HELLO
     */
    testHello() {
      const url = this.baseUrl + "/hello";
      axios.get(url).then(res => {
        console.log('res.data', res.data);
      }).catch(err => {
        console.log('err', err);
      })
    },
    /**
     * 访问"查询所有信息"接口
     * 成功返回 所有信息json
     */
    testGetAllRecords() {
      const url = this.baseUrl + "/findAll";
      axios.get(url).then(res => {
        console.log('res.data', res.data);

        this.allRecords = res.data;
      }).catch(err => {
        console.log('err', err);
      })
    },
    /**
     * 访问"插入数据"接口
     * 成功返回 “插入数据成功!”
     */
    testPostInsertRecord() {
      const url = this.baseUrl + "/insertRecord";
      axios({
        url: url,
        method: 'post',
        "content-type": "application/x-www-form-urlencoded",
        data: this.userInfo
      }).then((res) => {
        console.log("res.data:", res.data);
        // 插入成功后刷新数据
        this.testGetAllRecords();
      }).catch((err) => {
        console.log("err:", err);
      });
    },
  }
}
</script>

<style scoped>
.input-box p {
  display: inline-block;
  width: 60px;
}

table {
  background-color: aqua;
  margin: 20px auto;

}
</style>

  插入成功后自动刷新结果

 更新、删除以此类推

  六、全部代码

全部代码如下(点击展开)

后端代码:

UserController.java

package com.example.mydemo.controller;

import com.example.mydemo.entity.User;
import com.example.mydemo.mapper.UserMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@CrossOrigin
@RestController
@RequiredArgsConstructor
public class UserController {
    private final UserMapper userMapper;

    @GetMapping("/hello")
    public String hello() {
        return "HELLO";
    }

    @GetMapping("/findAll")
    public List<User> findAllUser() {
        return userMapper.queryAll();
    }

    @PostMapping("/insertRecord")
    public String insertUser(@RequestBody User user) {
        userMapper.insertRecord(user);
        return "插入数据成功!";
    }

    @PostMapping("/updateRecord")
    public String updateUser(@RequestBody User user) {
        userMapper.updateRecordById(user);
        return "更新数据成功!";
    }

    @DeleteMapping("/deleteRecord/{id}")
    public String deleteUser(@PathVariable int id) {
        userMapper.delRecordById(id);
        return "删除数据成功!";
    }
}
UserController.java

  UserMapper.java

package com.example.mydemo.mapper;

import com.example.mydemo.entity.User;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

public interface UserMapper {
    @Select("select * from user")
    List<User> queryAll();

    @Update("insert into user(name, age,grade) values(#{name}, #{age}, #{grade})")
    @Transactional
    void insertRecord(User user);

    @Update("update user set name=#{name}, age=#{age}, grade=#{grade} where id=#{id}")
    @Transactional
    void updateRecordById(User user);

    @Delete("delete from user where id=#{id}")
    @Transactional
    void delRecordById(int id);
}
UserMapper.java

 User.java

package com.example.mydemo.entity;

import lombok.Data;

@Data
public class User {
    private int id;
    private String name;
    private int age;
    private int grade;
}
User.java

MydemoApplication.java

package com.example.mydemo;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("com.example.mydemo.mapper")
public class MydemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(MydemoApplication.class, args);
    }

}
MydemoApplication.java

application.properties

spring.application.name=mydemo
server.port=8081

spring.datasource.url=jdbc:mysql://localhost:3306/test_springboot?useSSL=false&useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=1234
spring.datasource.driverClassName = com.mysql.cj.jdbc.Driver
application.properties

 前端代码

HelloWorld.vue

<template>
  <div class="hello">
    <h2>测试和 springboot 项目配合使用接口</h2>
    <div class="input-box">
      <p>name:</p>
      <input v-model="userInfo.name" />
      <br>
      <p>age:</p>
      <input v-model="userInfo.age" />
      <br>
      <p>grade:</p>
      <input v-model="userInfo.grade" />
    </div>
    <button @click="testPostInsertRecord">插入数据</button>
    <hr>

    <table cellspacing="10">
      <tr>
        <th>id</th>
        <th>name</th>
        <th>age</th>
        <th>grade</th>
        <th>操作</th>
      </tr>
      <tr v-for="record in allRecords" :key="record.id">
        <td>{{ record.id }}</td>
        <td>{{ record.name }}</td>
        <td>{{ record.age }}</td>
        <td>{{ record.grade }}</td>
        <td>
          <button @click="startUpdate(record)">更新</button>
          <button @click="testDelRecord(record)">删除</button>
        </td>
      </tr>
    </table>

    <div class="input-box" style="background-color: aquamarine;">
      <h4>在这里输入更新后的数据!</h4>
      <p>id:</p>
      <input v-model="updateRecord.id" disabled />
      <br>
      <p>name:</p>
      <input v-model="updateRecord.name" />
      <br>
      <p>age:</p>
      <input v-model="updateRecord.age" />
      <br>
      <p>grade:</p>
      <input v-model="updateRecord.grade" />
      <br>
      <button @click="testPostUpdateRecord()">确认更新</button>
    </div>
  </div>
</template>

<script>
import axios from "axios";

export default {
  name: 'HelloWorld',
  data() {
    return {
      baseUrl: "http://localhost:8081",
      allRecords: [],
      // 插入信息绑定的变量
      userInfo: {
        name: "",
        age: null,
        grade: null
      },
      // 更新信息绑定的变量
      updateRecord: {}
    }
  },
  mounted() {
    this.testGetAllRecords();
  },
  watch: {
    allRecords(newvalue, oldvalue) {
      console.log({ newvalue });
      console.log({ oldvalue });
    }
  },
  methods: {
    /**
     * 访问测试接口
     * 成功返回 HELLO
     */
    testHello() {
      const url = this.baseUrl + "/hello";
      axios.get(url).then(res => {
        console.log('res.data', res.data);
      }).catch(err => {
        console.log('err', err);
      })
    },
    /**
     * 访问"查询所有信息"接口
     * 成功返回 所有信息json
     */
    testGetAllRecords() {
      const url = this.baseUrl + "/findAll";
      axios.get(url).then(res => {
        console.log('res.data', res.data);

        this.allRecords = res.data;
      }).catch(err => {
        console.log('err', err);
      })
    },
    /**
     * 访问"插入数据"接口
     * 成功返回 “插入数据成功!”
     */
    testPostInsertRecord() {
      const url = this.baseUrl + "/insertRecord";
      axios({
        url: url,
        method: 'post',
        "content-type": "application/x-www-form-urlencoded",
        data: this.userInfo
      }).then((res) => {
        console.log("res.data:", res.data);
        // 插入成功后刷新数据
        this.testGetAllRecords();
      }).catch((err) => {
        console.log("err:", err);
      });
    },
    /**
     * 选中一行数据,准备进行更新
     */
    startUpdate(record) {
      this.updateRecord = record;
    },
    /**
     * 更新选中的记录
     */
    testPostUpdateRecord() {
      const url = this.baseUrl + "/updateRecord";

      axios({
        url: url,
        method: 'post',
        "content-type": "application/x-www-form-urlencoded",
        data: this.updateRecord
      }).then((res) => {
        console.log("res.data:", res.data);
        // this.testGetAllRecords();
      }).catch((err) => {
        console.log("err:", err);
      });
    },
    /**
     * 删除选中的记录
     */
    testDelRecord(record) {
      const url = this.baseUrl + "/deleteRecord/" + record.id;
      axios({
        url: url,
        method: 'delete',
      }).then((res) => {
        console.log("res.data:", res.data);
        this.testGetAllRecords();
      }).catch((err) => {
        console.log("err:", err);
      });
    }
  }
}
</script>

<style scoped>
.input-box p {
  display: inline-block;
  width: 60px;
}

table {
  background-color: aqua;
  margin: 20px auto;

}
</style>
HelloWorld.vue

七、 打包放到服务器上

 前端项目运行  npm run build  生成dist文件夹

复制文件夹内容,粘贴到 src/main/resources/static 下

 重启服务器,访问 http://localhost:8081/ 可以看到和前端项目一样的页面,并可以执行功能。

 

标签:VUE,console,err,url,res,分离,IDEA,import,data
From: https://www.cnblogs.com/sunshine233/p/18360207

相关文章

  • idea 2023.2安装教程(含激活码)长期有效
    申明:本教程IDEA补丁、补丁均收集于网络,请勿商用,仅供个人学习使用,如有侵权,请联系作者删除。若条件允许,希望大家购买正版!idea2023.2安装教程(含激活码)长期有效idea@ActivationCode使用流程Step1第一步下载IDEA软件Step2清空IDEA以前使用过激活方式Step3开始加......
  • .NET 7 + Vue 权限管理系统 小白快速上手
    前言今天给大家推荐一个超实用的开源项目《.NET7+Vue权限管理系统小白快速上手》,DncZeus的愿景就是做一个.NET领域小白也能上手的简易、通用的后台权限管理模板系统基础框架。不管你是技术小白还是技术大佬或者是不懂前端Vue的新手,这个项目可以快速上手让我们从0到1,搭建......
  • vue表单输入绑定
    使用v-model指令实现双向数据绑定的集合v-model是v-on和v-bind指令的语法糖(指令集合)可以使用v-model指令在表单input、textarea、select等元素上创建双向数据绑定,他会根据控件类型自动选取正确的方法来更新元素。加上v-model后,只要视图的数据发生了改变,那么vm中的model层的......
  • 基于SpringBoot+MySQL+SSM+Vue.js的药房药品采购系统(附论文)
    获取见最下方名片获取见最下方名片获取见最下方名片演示视频技术描述开发工具:Idea/Eclipse数据库:MySQLJar包仓库:Maven前端框架:Vue/ElementUI后端框架:Spring+SpringMVC+Mybatis+SpringBoot文字描述基于SpringBoot+MySQL+SSM+Vue.js的药房药品采购系统(附论文......
  • 基于SpringBoot+MySQL+SSM+Vue.js的旅游咨询系统
    获取见最下方名片获取见最下方名片获取见最下方名片演示视频技术描述开发工具:Idea/Eclipse数据库:MySQLJar包仓库:Maven前端框架:Vue/ElementUI后端框架:Spring+SpringMVC+Mybatis+SpringBoot文字描述基于SpringBoot+MySQL+SSM+Vue.js的旅游咨询系统,用户,管理......
  • vue按键修饰符
    事件的类型有以下四类:js事件分为四类:鼠标事件:click、mouseover、dbclick、mousedown、mouseout...键盘事件:keydown、keypress、keyup..窗体事件:load、reseize、scroll...表单事件:blur、focus、input、change、select传统方式的弊端:需要了解每个数值的键码为了在必要的......
  • 040.Vue3入门,在Vue3中引入ElementUI
    1、npminstallelement-plus--save,安装UI 2、main.js代码如下://import'./assets/main.css'//引入下面这两行importElementPlusfrom'element-plus'import'element-plus/dist/index.css'import{createApp}from'vue'importApp......
  • vue 组件调用组件自身,递归调用组件自身
    父组件<template><divclass="page-box"><!--<child><templatev-slot:default="scope"><div>slot</div><div>{{scope.data1}}</div>......
  • vue事件修饰符
    我们用vue中的事件修饰符来做上一篇中event.preventDefault() 阻止事件的默认行为和event.stopPropagation() 阻止事件冒泡、传播事件。<divid="app"><div@click="outer"id="outer"><div@click="middle"id="middle"&......
  • 云计算实训28——haproxy(七层代理)、python代码的读写分离
    一、haproxy----高可用、负载均衡1.安装安装ntpdate[root@haproxy~]#yum-yinstallntpdate.x86_64安装ntp[root@haproxy~]#yum-yinstallntp同步时间[root@haproxy~]#ntpdatecn.ntp.org.cn启动ntp服务[root@haproxy~]#systemctlstartntpd设置开机自......