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

参考链接:

环境要求:

  • 安装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/ 可以看到和前端项目一样的页面,并可以执行功能。

 

posted @ 2024-08-15 11:48  sunshine233  阅读(966)  评论(0编辑  收藏  举报