目录
最近两天刚刚学习完Springboot,决定做一个demo整合一下学习到的知识。由于前端所知甚少,所以前端会有一些小bug,但总的来说不影响功能。
技术栈
后端:
框架:Springboot、Mybatis、PageHelper(分页小工具)
工具:IDEA、Maven
数据库:Mysql 5
前端:
框架:Vue、axios、qs、element ui
工具:VS、npm、webpack
开发过程中遇到的问题:
- 跨域问题
- 因为前后端工程在不同的服务器上,端口不同所以存在跨域问题
- 解决方法: 代理服务器
- 参数传递问题
- axios默认的请求参数时json格式的,后端接受的可能是单独的参数如String name等
- 解决方法:qs
后端开发过程
- 搭建工程
- 利用mybatis逆向工程生成实体类、Dao接口、mapper文件
- 在springboot配置文件中配置数据库信息、端口号等
- 编写controller
- 先确定接口的请求参数、响应数据
- 最终的接口有:
- 分页查询:使用pageHelper,
- 请求参数为pageNum、pageSize即页码和页面大小,页面大小由前端控制
- 响应数据为json数组,数组中存储的为多个实体类的信息
- 添加:请求参数为实体类对象,响应数据为json字符串:成功或失败
- 删除:请求参数为主键id值,响应数据为json字符串:成功或失败
- 修改:请求参数为实体类对象,响应数据为json字符串:成功或失败
- 获取数据库的总条数:无请求参数,响应数据为json字符串:数据库的数据总条数,用于前端获取总页数
- 分页查询:使用pageHelper,
- 根据controller编写service
- 根据service在dao中增加方法
后端代码
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.wm</groupId>
<artifactId>springboot-crud-demo</artifactId>
<version>1.0.0</version>
<name>springboot-crud-demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--thymeleaf依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--springboot起步依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--mybatis集成springboot依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.3</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!-- 数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.12</version>
</dependency>
<!--分页依赖-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.13</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<!--指定mapper文件位置-->
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<!--逆向工程插件-->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.7</version>
<configuration>
<configurationFile>generatorConfig.xml</configurationFile>
<verbose>true</verbose>
<overwrite>true</overwrite>
</configuration>
</plugin>
<!--springboot打包插件-->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.properties
server.port=9090
#设置连接数据库
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/spring?characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
StudentController.java
package com.wm.controller;
import com.wm.model.Student;
import com.wm.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.List;
@RequestMapping("/student")
@Controller
public class StudentController {
@Autowired
StudentService studentService;
@RequestMapping(value = "/pageQuery")
@ResponseBody
public List<Student> pageQuery(Integer pageNum, Integer pageSize, HttpServletResponse response){
response.setHeader("Access-Control-Allow-Origin", "*");
return studentService.pageQueryStudent(pageNum, pageSize);
}
@ResponseBody
@RequestMapping(value = "/insertStudent")
public String insertStudent(Student student){
Boolean flag = studentService.insertStudent(student);
return flag? "添加成功" : "添加失败";
}
@ResponseBody
@RequestMapping(value = "/deleteStudent")
public String deleteStudent(Integer id){
Boolean flag = studentService.deleteStudent(id);
return flag? "删除成功" : "删除失败";
}
@ResponseBody
@RequestMapping("/getTotal")
public Integer getTotal(){
return studentService.getTotal();
}
@ResponseBody
@RequestMapping(value = "/updataStudent")
public String deleteStudent(Student student){
Boolean flag = studentService.updataStudent(student);
return flag? "更新成功" : "更新失败";
}
}
StudentServiceImpl.java
package com.wm.service.impl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.wm.mapper.StudentMapper;
import com.wm.model.Student;
import com.wm.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class StudentServiceImpl implements StudentService {
@Autowired
StudentMapper studentMapper;
@Override
public List<Student> pageQueryStudent(Integer pageNum, Integer pageSize) {
PageHelper.startPage(pageNum, pageSize);
List<Student> studentList = studentMapper.selectAll();
return studentList;
}
@Override
public Boolean insertStudent(Student student) {
int i = studentMapper.insertSelective(student);
return i>0 ? true:false;
}
@Override
public Boolean deleteStudent(Integer id) {
int i = studentMapper.deleteByPrimaryKey(id);
return i>0 ? true:false;
}
@Override
public Integer getTotal() {
return studentMapper.getTotal();
}
@Override
public Boolean updataStudent(Student student) {
int i = studentMapper.updateByPrimaryKeySelective(student);
return i > 0 ? true : false;
}
}
StudentMapper.java
package com.wm.mapper;
import com.wm.model.Student;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface StudentMapper {
int deleteByPrimaryKey(Integer id);
int insert(Student record);
int insertSelective(Student record);
Student selectByPrimaryKey(Integer id);
int updateByPrimaryKeySelective(Student record);
int updateByPrimaryKey(Student record);
List<Student> selectAll();
Integer getTotal();
}
StudentMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.wm.mapper.StudentMapper">
<resultMap id="BaseResultMap" type="com.wm.model.Student">
<id column="id" jdbcType="INTEGER" property="id" />
<result column="name" jdbcType="VARCHAR" property="name" />
<result column="age" jdbcType="INTEGER" property="age" />
<result column="address" jdbcType="VARCHAR" property="address" />
</resultMap>
<sql id="Base_Column_List">
id, name, age, address
</sql>
<select id="getTotal" resultType="java.lang.Integer">
select count(id) from student
</select>
<select id="selectAll" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from student
</select>
<select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from student
where id = #{id,jdbcType=INTEGER}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
delete from student
where id = #{id,jdbcType=INTEGER}
</delete>
<insert id="insert" parameterType="com.wm.model.Student">
insert into student (id, name, age,
address)
values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, #{age,jdbcType=INTEGER},
#{address,jdbcType=VARCHAR})
</insert>
<insert id="insertSelective" parameterType="com.wm.model.Student">
insert into student
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">
id,
</if>
<if test="name != null">
name,
</if>
<if test="age != null">
age,
</if>
<if test="address != null">
address,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
#{id,jdbcType=INTEGER},
</if>
<if test="name != null">
#{name,jdbcType=VARCHAR},
</if>
<if test="age != null">
#{age,jdbcType=INTEGER},
</if>
<if test="address != null">
#{address,jdbcType=VARCHAR},
</if>
</trim>
</insert>
<update id="updateByPrimaryKeySelective" parameterType="com.wm.model.Student">
update student
<set>
<if test="name != null">
name = #{name,jdbcType=VARCHAR},
</if>
<if test="age != null">
age = #{age,jdbcType=INTEGER},
</if>
<if test="address != null">
address = #{address,jdbcType=VARCHAR},
</if>
</set>
where id = #{id,jdbcType=INTEGER}
</update>
<update id="updateByPrimaryKey" parameterType="com.wm.model.Student">
update student
set name = #{name,jdbcType=VARCHAR},
age = #{age,jdbcType=INTEGER},
address = #{address,jdbcType=VARCHAR}
where id = #{id,jdbcType=INTEGER}
</update>
</mapper>
Student.java
package com.wm.model;
import java.io.Serializable;
public class Student implements Serializable {
private Integer id;
private String name;
private Integer age;
private String address;
private static final long serialVersionUID = 1L;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name == null ? null : name.trim();
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address == null ? null : address.trim();
}
}
SpringbootCrudDemoApplication.java
package com.wm;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan(basePackages = "com.wm.mapper")
public class SpringbootCrudDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootCrudDemoApplication.class, args);
}
}
前端开发过程
- 搭建工程
- 通过vue ui 创建工程
- 安装axios、element ui、qs
- 在项目目录下创建vue.config.js 用于配置端口和解决跨域问题
- 利用element ui 官网,复制粘贴你需要的组件
- 给组件添加事件,利用axios发生ajax请求接受响应数据并展示
前端代码
src\components\HelloWorld.vue
<template>
<div>
<el-container>
<el-header>
<el-row :gutter="20">
<el-col :span="5">
<el-input v-model="addStudentInfo.name" placeholder="请输入姓名"></el-input>
</el-col>
<el-col :span="5">
<el-input v-model="addStudentInfo.age" placeholder="请输入年龄"></el-input>
</el-col>
<el-col :span="5">
<el-input v-model="addStudentInfo.address" placeholder="请输入地址"></el-input>
</el-col>
<el-col :span="4">
<el-button type="primary" @click="addStudent">添加</el-button>
</el-col>
<el-col :span="4">
<el-button type="danger">删除</el-button>
</el-col>
</el-row>
</el-header>
<el-main>
<el-table :data="tableData" style="width: 100%">
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column prop="id" label="序号" width="180"></el-table-column>
<el-table-column prop="name" label="姓名" width="180"></el-table-column>
<el-table-column prop="age" label="年龄" width="180"></el-table-column>
<el-table-column prop="address" label="地址"></el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button type="primary" icon="el-icon-edit" circle @click="updataDialog(scope.$index, scope.row)"></el-button>
<el-dialog title="修改信息" :visible.sync="dialogFormVisible">
<el-form :model="updataStudentInfo">
<el-form-item label="姓名">
<el-input v-model="updataStudentInfo.name" placeholder="请输入姓名"></el-input>
</el-form-item>
<el-form-item label="年龄">
<el-input v-model="updataStudentInfo.age" placeholder="请输入年龄"></el-input>
</el-form-item>
<el-form-item label="地址">
<el-input v-model="updataStudentInfo.address" placeholder="请输入地址"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="updataStudent()">确 定</el-button>
</div>
</el-dialog>
<el-popconfirm title="这是一段内容确定删除吗?" @onConfirm="deleteStudent(scope.$index, scope.row)">
<el-button type="danger" icon="el-icon-delete" circle slot="reference"></el-button>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
<el-pagination background layout="prev, pager, next" :total="total" :page-size="pageSize"
@current-change="pageChange" :current-page.sync="currentPage">
</el-pagination>
</el-main>
</el-container>
</div>
</template>
<script>
export default {
data() {
return {
addStudentInfo: {
name: null,
age: null,
address: null,
},
updataStudentInfo: {
di: null,
name: null,
age: null,
address: null,
},
tableData: [{
id: null,
name: null,
age: null,
address: null,
}, ],
pageSize: 4,
currentPage: null,
total: null,
//控制编辑按钮 弹出from表单,true为弹出
dialogFormVisible: false,
};
},
mounted() {
this.getTotal();
this.pageChange();
},
methods: {
//更新信息
updataStudent(){
if (this.updataStudentInfo.name == null ||
this.updataStudentInfo.age == null ||
this.updataStudentInfo.address == null) {
this.$message.error('请完整输入信息');
return
} else if (!/^[0-9]*$/.test(this.updataStudentInfo.age)) {
this.$message.error('年龄只能为数字');
return
}
let postData = this.qs.stringify({
id: this.updataStudentInfo.id,
name: this.updataStudentInfo.name,
age: this.updataStudentInfo.age,
address: this.updataStudentInfo.address,
});
this.axios({
method: 'post',
url: '/student/updataStudent',
data: postData,
})
.then(response => (
this.$message(response.data)
))
.catch(function (error) {
console.log(error);
})
this.pageChange();
this.dialogFormVisible = false;
},
//弹出更新信息框
updataDialog(index, row){
this.dialogFormVisible = true;
this.updataStudentInfo = {
id: row.id,
name: row.name,
age: row.age,
address: row.address
}
},
//删除学生
deleteStudent(index, row) {
let postData = this.qs.stringify({
id: row.id
});
this.axios({
method: 'post',
url: '/student/deleteStudent',
data: postData,
})
.then(response => (
this.$message(response.data)
))
.catch(function (error) {
console.log(error);
})
this.pageChange();
},
//添加学生
addStudent() {
if (this.addStudentInfo.name == null ||
this.addStudentInfo.age == null ||
this.addStudentInfo.address == null) {
this.$message.error('请完整输入信息');
return
} else if (!/^[0-9]*$/.test(this.addStudentInfo.age)) {
this.$message.error('年龄只能为数字');
return
}
let postData = this.qs.stringify({
name: this.addStudentInfo.name,
age: this.addStudentInfo.age,
address: this.addStudentInfo.address,
});
this.axios({
method: 'post',
url: '/student/insertStudent',
data: postData,
})
.then(response => (
this.$message(response.data)
))
.catch(function (error) {
console.log(error);
})
this.getTotal();
this.pageChange();
this.addStudentInfo = {
name: null,
age: null,
address: null,
}
},
//获取数据库中的总数的方法
getTotal() {
this.axios({
method: 'post',
url: '/student/getTotal',
})
.then(response => (this.total = response.data))
.catch(function (error) {
console.log(error);
})
},
//分页查询,改变页数时会执行的方法
pageChange() {
let postData = this.qs.stringify({
pageNum: this.currentPage,
pageSize: this.pageSize
});
this.axios({
method: 'post',
url: '/student/pageQuery',
data: postData,
})
.then(response => (this.tableData = response.data))
.catch(function (error) {
console.log(error);
})
}
}
};
</script>
<style>
</style>
src\views\Home.vue
<template>
<div class="home">
<HelloWorld msg="首页"/>
</div>
</template>
<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'
export default {
name: 'Home',
components: {
HelloWorld
}
}
</script>
src\App.vue
<template>
<div id="app">
<div id="nav">
<router-link to="/">首页</router-link> |
<router-link to="/about">关于</router-link>
</div>
<router-view/>
</div>
</template>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
#nav {
padding: 30px;
}
#nav a {
font-weight: bold;
color: #2c3e50;
}
#nav a.router-link-exact-active {
color: #42b983;
}
</style>
src\main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import ElementUI from 'element-ui';
import axios from 'axios'
import 'element-ui/lib/theme-chalk/index.css';
import VueAxios from 'vue-axios'
import qs from 'qs'
Vue.use(VueAxios, axios, qs)
Vue.config.productionTip = false
Vue.use(ElementUI);
new Vue({
router,
render: h => h(App)
}).$mount('#app')
vue.config.js
解决跨域问题最关键的一步
module.exports = {
devServer: {
host: 'localhost',
port: 8084,
//以上的ip和端口是我们本机的;下面为需要跨域的
proxy: { //配置跨域
'/student': {
target: 'http://localhost:9090', //这里后台的地址模拟的;应该填写你们真实的后台接口
changOrigin: true, //允许跨域
}
}
}
}
实现效果: