Vue+Spring boot+mysql前后端连接实现增删改查
前后端及其连接一共四大步骤,1.建库 2.后端定义功能 3.前端实现界面 4.前后端连接1.MYSQL建库建一个department表2.后端定义功能——在Spring boot工程里把接口写好小前言1:理解层次的概念总的来说,一共一组实体+3层实体:实体的类名为表的名字,实体的参数为表的参数最底层:通过SQL语句实现对数据库的操纵,可以理解为基本动作(如武术里的跑,跳,出拳)中间层:使用最底层的
·
前后端及其连接
一共四大步骤,1.建库 2.后端定义功能 3.前端实现界面 4.前后端连接
1.MYSQL建库
建一个department表
2.后端定义功能——在Spring boot工程里把接口写好
小前言1:理解层次的概念
总的来说,一共一组实体+3层
实体:实体的类名为表的名字,实体的参数为表的参数
最底层:通过SQL语句实现对数据库的操纵,可以理解为基本动作(如武术里的跑,跳,出拳)
中间层:使用最底层的基本操作,组合一下就是中间层的升级操作动作(如跑加跳,跑加出拳,跳加出拳等)
最上层:使用中间层的基本操作,组合成实现业务逻辑的操作(如跑加跳 +跑加出拳 组合成跑跳出拳连招 )
层次与目录结构如下
0、application.properties的配置代码
注:在数据库配置里要把数据库名,账号密码换成自己的
# 应用服务端口
server.port=8080
# 数据库配置
spring.datasource.url=jdbc:mysql://localhost:3306/day7.8test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&sessionVariables=sql_mode='NO_ENGINE_SUBSTITUTION'
spring.datasource.username=root
spring.datasource.password=2333
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# mybatis的 Mapping.xml的位置
mybatis.mapper-locations=classpath:mapping/*Mapping.xml
# 指定POJO扫描包来让mybatis自动扫描到自定义的POJO,如果配置了该配置则不需要再ResultMap中指定全类名了
mybatis.type-aliases-package=com.ustc.learn.mybatis.entity
#全局性地开启或关闭所有映射器配置文件中已配置的任何缓存
mybatis.configuration.cache-enabled=false
#延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态
mybatis.configuration.lazy-loading-enabled=false
# 开启时,任一方法的调用都会加载该对象的所有延迟加载属性。 否则,每个延迟加载属性会按需加载(参考 lazyLoadTriggerMethods)
mybatis.configuration.aggressive-lazy-loading=true
#更多mybatis的配置请参考 https://mybatis.org/mybatis-3/zh/configuration.html#properties
# 打印sql
logging.level.com.ustc.learn.mybatis=DEBUG
######### 分页插件 ##########
#配置使用哪种数据库语言,不配置的话pageHelper也会自动检测
pagehelper.helper-dialect=mysql
#为了支持startPage(Object params)方法,增加了该参数来配置参数映射,用于从对象中根据属性名取值;
# 可以配置 pageNum,pageSize,count,pageSizeZero,reasonable,不配置映射的用默认值,
# 默认值为pageNum=pageNum;pageSize=pageSize;count=countSql;reasonable=reasonable;pageSizeZero=pageSizeZero。
pagehelper.params=count=countSql
#配置分页参数合理化功能,默认是false。 #启用合理化时,如果pageNum<1会查询第一页,如果pageNum>总页数会查询最后一页;
#禁用合理化时,如果pageNum<1或pageNum>总页数会返回空数据。
pagehelper.reasonable=false
#支持通过Mapper接口参数来传递分页参数,默认值false,分页插件会从查询方法的参数值中,自动根据上面 params 配置的字段中取值,查找到合适的值时就会自动分页。
pagehelper.support-methods-arguments=true
1、实体与数据库对应
@Data //自动为private添加get/set方法
public class department {
private String departmentName;
private int rank;
private String state;
private String createTime;
}
2、实现底层——用于与数据库交互
有两种方式:
一种是mapper+xml的方式
一种是直接mapper里实现
注:这两种方式可以混用
mapper里的内容
@Mapper
public interface departmentMapper {
/*方式1: mapper+xml的方式 在mapper里定义方法接口,在xml里实现语句 */
//@Param用于解释右边的数据,传入时无论右边写了什么,都传@Param里的名字
public List<department> findByDname(@Param("departmentName") String departmentName);
public List<department> findByRank(@Param("rank") int rank);
public void add(@Param("departmentName") String departmentName,@Param("rank") int rank);
public void updatedepartment(@Param("state") String state,@Param("departmentName") String departmentName);
public void delStudentByRank(@Param("departmentName") String departmentName);
/*方式2: 直接mapper方式 在mapper里定义方法并实现 */
@Select("select * from department")
public List<department> findAll();
}
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">
<!--namespace是用于绑定Dao接口的,即面向接口编程-->
<!--修改1-->
<mapper namespace="com.ustc.learn.mybatis.mapper.departmentMapper">
<!--修改2-->
<resultMap id="departmentResultMap" type="com.ustc.learn.mybatis.entity.department">
<!-- 修改3 主键设置-->
<id column="departmentName" jdbcType="VARCHAR" property="departmentName"/>
<id column="rank" jdbcType="INTEGER" property="rank"/>
<!-- 修改4非主键类且JDBC没datetime属性,只有date或time -->
<result column="state" jdbcType="VARCHAR" property="state"/>
<result column="createTime" jdbcType="DATE" property="createTime"/>
</resultMap>
<select id="findByDname" resultMap="departmentResultMap">
-- concat是Mysql里的字符串拼接
select * from department where departmentName like concat('%', #{departmentName},'%')
</select>
<select id="findByRank" resultMap="departmentResultMap">
select * from department where rank = #{rank}
</select>
<insert id="add" parameterType="com.ustc.learn.mybatis.entity.department">
insert into department values(#{departmentName},#{rank},"正常","2021-07-11 20:27:05")
</insert>
<update id="updatedepartment" parameterType="com.ustc.learn.mybatis.entity.department">
update department set state = #{state} where departmentName = #{departmentName}
</update>
<delete id="delStudentByRank" parameterType="com.ustc.learn.mybatis.entity.department">
delete from department where departmentName = #{departmentName}
</delete>
</mapper>
3、实现中间层
@Service
public class departmentService {
@Resource
private departmentMapper dpmMapper;
public List<department> findByDname(String departmentName){
return dpmMapper.findByDname(departmentName);
}
public List<department> findByRank(int rank){
return dpmMapper.findByRank(rank);
};
public void add(String departmentName,int rank){
dpmMapper.add(departmentName,rank);
};
public void updatedepartment(String state, String departmentName){
dpmMapper.updatedepartment(state,departmentName);
};
public void delStudentByRank(@Param("departmentName") String departmentName){
dpmMapper.delStudentByRank(departmentName);
};
public List<department> findAll(){
return dpmMapper.findAll();
}
}
4、实现最上层
@RestController
@Slf4j
@RequestMapping(value = "/department")
@Api(value = "部门接口", tags = "部门相关的接口" )
public class departmentController {
@Autowired
private departmentService dpmS;
@RequestMapping(value = "/findAllD")
public List<department> findAll(){
return dpmS.findAll();
}
@RequestMapping(value = "/findByDname" ,method = RequestMethod.POST)
public List<department> findByDname(@RequestBody Map<String,String> maps){
return dpmS.findByDname(maps.get("departmentName"));
};
@RequestMapping(value = "/findByRank",method = RequestMethod.POST)
public List<department> findByRank( int rank){
return dpmS.findByRank(rank);
};
@PutMapping(value = "/addDandR") //String departmentName,int rank
public void add(@RequestBody Map<String,String> maps ){
int myrank= Integer.parseInt(maps.get("rank"));
dpmS.add(maps.get("departmentName"),myrank);
};
@PutMapping(value = "/updatedepartment")
public void updatedepartment(String state,String departmentName){
dpmS.updatedepartment(state,departmentName);
};
@DeleteMapping(value = "/delStudentByRank")
public void delStudentByRank(@RequestBody Map<String,String> maps){
System.out.println("controller begin");
dpmS.delStudentByRank(maps.get("departmentName"));
System.out.println("controller over");
};
3.前端实现界面与连接——在Vue里把页面写好
目录结构
3.1实现前后端连接的语句——axios
在main.js里加以下两句话
import axios from 'axios'
Vue.prototype.$http = axios
3.2解决端口共用问题
由于前后端默认打开时都是占用8080端口,而一个端口只能被一个占用
解决方案:需要先run 后端工程,再run前端工程才能分别占用两个端口
3.3解决跨域问题
- 跨域问题的定义:
产生原因,SPring boot + vue里的跨域问题以及前端解决方案
假如是在同一台机器上开发,前后端分离的工程中出现跨域问题的原因是,前端工程和后端工程运行在不同的端口上。只要协议、域名、端口有一个不同就会产生跨域问题,所以在前端工程中请求后端的接口时就会因为端口不同而产生跨域问题。
2.前端方法
proxyTable: {
// 跨域问题的解决
'/api':{
target:"http://localhost:8080",
changeOrigin:true,
pathRewrite:{
'^/api':'/'
}
}
},
3.4实现页面与动作
APP.VUE
<template>
<div id="app" >
<router-view/>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
margin: 0;
width: 100%;
height: 100%;
position: relative;
}
</style>
Helloworld.vue
<template>
<div>
<div>
<form class="layui-form" action="">
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">部门名称</label>
<div class="layui-input-inline">
<!--v-model用于传参,把表单里的值给Dname变量-->
<input type="tel" name="phone" lay-verify="required|phone" autocomplete="off" class="layui-input" v-model="Dname">
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">状态</label>
<div class="layui-input-inline">
<input type="text" name="email" lay-verify="email" autocomplete="off" class="layui-input">
</div>
<button @click="getText" type="button" class="layui-btn layui-btn-primary" style="background-color: deepskyblue;color: white">搜索</button>
<button type="button" class="layui-btn layui-btn-primary" >重置</button>
</div>
</div>
</form>
<div>
<table border="1" style="background-color: #9F9F9F;border-left: none;border-right: none;border-color: #9F9F9F">
<tr>
<td >部门名称</td> <td>排序</td> <td>状态</td> <td>创建时间</td>
</tr>
<!--v-for用于循环取a中每个元素-->
<tr v-for="j in a">
<td>{{j.departmentName}}</td>
<td>{{j.rank}}</td>
<td>{{j.state}}</td>
<td>{{j.createTime}}</td>
</tr>
</table>
</div>
</div>
<div style="position: absolute;right: 0px;top: 0;width: 500px;height: 400px;background-color: ghostwhite">
<form class="layui-form" action="" >
<div class="layui-form-item">
<label class="layui-form-label">部门名称:</label>
<div class="layui-input-block">
<input type="text" name="title" lay-verify="title" autocomplete="off" placeholder="请输入标题" class="layui-input" style="width: 300px" v-model="Dname">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">部门排序:</label>
<div class="layui-input-block">
<input type="text" name="username" lay-verify="required" lay-reqText="用户名是必填项,岂能为空?" placeholder="请输入" autocomplete="off" class="layui-input" style="width: 300px" v-model="Rank">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">部门状态:</label>
<div class="layui-input-block">
<input type="text" name="username" lay-verify="required" lay-reqText="用户名是必填项,岂能为空?" placeholder="请输入" autocomplete="off" class="layui-input" style="width: 300px">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">创建时间:</label>
<div class="layui-input-block">
<input type="text" name="username" lay-verify="required" lay-reqText="用户名是必填项,岂能为空?" placeholder="请输入" autocomplete="off" class="layui-input" style="width: 300px">
</div>
</div>
<!--@click="addText"用于绑定点击事件对应的触发函数-->
<button type="button" class="layui-btn layui-btn-primary" @click="addText" >确定添加</button>
<button type="button" class="layui-btn layui-btn-primary" @click="delText" >确定删除</button>
<button type="button" class="layui-btn layui-btn-primary" >确定修改</button>
</form>
</div>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
msg: 'Welcome to Your Vue.js App',
Dname:"",
Rank:"",
a:[
{departmentName:'',
rank:'',
state:'',
createTime:''},
{departmentName:'',
rank:'',
state:'',
createTime:''},
{departmentName:'',
rank:'',
state:'',
createTime:''},
{departmentName:'',
rank:'',
state:'',
createTime:''},
{departmentName:'',
rank:'',
state:'',
createTime:''},
{departmentName:'',
rank:'',
state:'',
createTime:''},
]
}
},
methods:{
//getText的请求是post类型的,因此是$http.post
getText(){
var that =this;
this.$http.post("/api/department/findByDname",{departmentName: that.Dname})
.then((res)=>{
console.log(res);
for( var i=0;i<6;i++){
that.a[i].departmentName = "";
that.a[i].rank = "";
that.a[i].state = "";
that.a[i].createTime = "";
}
// 这里res.data返回的是0,1,2,3....之类的数字
for(var i in res.data){
that.a[i].departmentName = res.data[i].departmentName;
that.a[i].rank = res.data[i].rank;
that.a[i].state = res.data[i].state;
that.a[i].createTime = res.data[i].createTime;
}
})
},
//addtext对应链接的请求是put类型的,因此这里是$http.put
addText(){
var that =this;
this.$http.put("/api/department/addDandR",{departmentName:that.Dname,rank:that.Rank})
.then((res)=>{
}
)
},
//addtext对应链接的请求是delete类型的,因此这里是$http.delete
delText(){
var that =this;
this.$http.delete("/api/department/delStudentByRank",{data:{departmentName:that.Dname}})
.then((res)=>{
}
)
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
td{
width: 100px;
height: 50px;
padding-left: 20px;
}
</style>
结束:数据流备注
——VUE工程里前端表单里的数据输入传入后端再到数据库的呢?
1.在表单里添加v-model属性(类似v-bind)
v-model = "data里的某一个变量名"
这样前端的数据就传入了data的变量里
2.再在方法里利用axios的方式使用变量,
即可将变量的数据传入后端的最顶层,即controller层
3.最后controller层调用中间层再调用底层,即可完成对数据库的操作
swagger测试
端口默认8080
http://localhost:8080/swagger-ui.html#/
更多推荐
已为社区贡献2条内容
所有评论(0)