SSM整合-前后端分离-实现增删改查 (下)

主流框架SSM

  • 实现功能03-添加家居信息
    • 需求分析/图解
    • 思路分析
    • 代码实现
    • 注意事项和细节
  • 实现功能04-显示家居信息
    • 需求分析/图解
    • 思路分析
    • 代码实现
  • 实现功能05-修改家居信息
    • 需求分析/图解
    • 思路分析
    • 代码实现
    • 注意事项和细节
  • 实现功能06-删除家居信息
    • 需求分析/图解
    • 思路分析
    • 代码实现
    • 课后作业
  • 实现功能07-分页显示列表
    • 需求分析/图解
    • 思路分析
    • 代码实现
    • 完成测试
  • 实现功能08-带条件查询分页显示列表
    • 需求分析/图解
    • 思路分析
    • 代码实现
  • 实现功能09-添加家居表单前端校验
    • 需求分析/图解
    • 思路分析
    • 代码实现
  • 实现功能10-添加家居表单后端校验
    • 需求分析/图解
    • 思路分析
    • 代码实现
  • SSM项目[前后端分离]小结+作业要求

在这里插入图片描述

上一章, SSM整合-前后端分离-项目环境搭建 (上)

实现功能03-添加家居信息

需求分析/图解

在这里插入图片描述

在这里插入图片描述

思路分析

1.完成后台代码从 dao -> service -> controller, 并对每层代码进行测试, 到controller这一层, 使用Postman 发送http post请求完成测试.

2.完成前端代码, 使用axios发送ajax(json数据)给后台, 实现添加家居信息

代码实现

回忆JavaWeb版本家居购项目
在这里插入图片描述

1创建src/main/java/com/zzw/furn/service/FurnService.java

public interface FurnService {//添加public void save(Furn furn);
}

2.创建src/main/java/com/zzw/furn/service/impl/FurnServiceImpl.java

@Service
public class FurnServiceImpl implements FurnService {//注入/装配FurnMapper接口对象[代理对象]@Resourceprivate FurnMapper furnMapper;@Overridepublic void save(Furn furn) {//解读//1.使用insertSelective//2.因为我们furn表的id是自增的, 就使用insertSelectivefurnMapper.insertSelective(furn);}
}

3.测试 src/test/java/com/zzw/furn/service/FurnServiceTest.java
动态代理jdk的Proxy和Spring的CGlib, getBean方法何时会返回代理对象

public class FurnServiceTest {//属性private ApplicationContext ioc;//从spring容器中,获取的是FurnService接口对象/代理对象private FurnService furnService;/*** 解读* 1. 编写方法完成初始化* 2. 当方法标注 @Before, 表示在执行你的目标测试方法前, 会先执行该方法*/@Beforepublic void init() {ioc = new ClassPathXmlApplicationContext("applicationContext.xml");String[] beanDefinitionNames = ioc.getBeanDefinitionNames();//说明//1.通过FurnService.class类型获取 FurnService接口代理对象furnService = ioc.getBean(FurnService.class);System.out.println("furnService=" + furnService.getClass());}@Testpublic void save() {Furn furn =new Furn(null, "你好", "你好", new BigDecimal(100), 123, 2, "image");furnService.save(furn);System.out.println("添加成功");}
}

4.修改Furn.java, 当创建Furn对象 imgPathnull时, imgPath给默认值

//当创建Furn对象 imgPath 为 null时, imgPath 给默认值
private String imgPath = "assets/images/product-image/1.jpg";public Furn(Integer id, String name, String maker, BigDecimal price, Integer sales, Integer stock, String imgPath) {this.id = id;this.name = name;this.maker = maker;this.price = price;this.sales = sales;this.stock = stock;//解读//如果imgPath不为null, 而且是有数据, 就设置给this.imgPath; 否则就使用默认值//imgPath != null && !imgPath.equals("") => 使用一个工具类方法完成 => org.springframework.util//public static boolean hasText(@Nullable String str) {//    return str != null && !str.isEmpty() && containsText(str);//}//StringUtils.hasText(imgPath) 就是要求imgPath 不是null, 而且不是"", 而且不是"    "if (StringUtils.hasText(imgPath)) {this.imgPath = imgPath;} else {this.imgPath = "assets/images/product-image/1.jpg";}
}

5.创建src/main/java/com/zzw/furn/bean/Msg.java, 用来返回json数据的通用类.

/*** Msg: 后端程序返回给前端的json数据的Msg对象=>本质就是数据规则*/
@Getter
@Setter
public class Msg {//状态码 200-成功 400-失败private int code;//信息-返回数据的说明private String msg;//返回给客户端/浏览器的数据-Map集合private Map<String, Object> extend = new HashMap<>();//编写几个常用的方法-封装好msg//返回success对应的msgpublic static Msg success() {Msg msg = new Msg();msg.setCode(200);msg.setMsg("success");return msg;}//返回fail对应的msgpublic static Msg fail() {Msg msg = new Msg();msg.setCode(400);msg.setMsg("fail");return msg;}//给返回的msg设置数据public Msg add(String key, Object value) {extend.put(key, value);return this;}
}

6.创建com/zzw/furn/controller/FurnController.java,处理添加请求.

@Controller
public class FurnController {//注入配置FurnService@Resourceprivate FurnService furnService;/*** 1.响应客户端的添加请求* 2.@RequestBody:* 使用SpringMVC的 @RequestBody 将客户端提交的json数据, 封装成JavaBean对象* 3.@ResponseBody:* 我们往往需要服务器返回的数据格式是按照json来返回的(底层是按照http协议进行协商)** @param furn* @return*/@PostMapping("/save")@ResponseBodypublic Msg save(@RequestBody Furn furn) {furnService.save(furn);//没有抛出异常, 就返回成功信息Msg success = Msg.success();return success;}
}

7.使用Postman来完成Controller层测试, 通过Postman添加Furn数据

1)使用Postman进行测试. Postman如何发送json数据

{"name":"海澜之家衣柜","maker":"小米之家","price":13.3,"sales":300,"stock":1000
}

2)使用Postman测试时, 因为我们前台发送的是json数据, 被服务器接收到后, 转成javabean数据, 因此pom.xml需要引入jackson, 处理json数据, 否则后台会报错.

<!--引入jackson, 处理json数据-->
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.12.4</version>
</dependency>

8.点击添加按钮, 可以出现添加家居的对话框, 修改D:\idea_project\SSM-Vue整合项目\ssm_vue\src\views\HomeView.vue.
说明一下 el-dialog从Dialog对话框获取▶️, 表单代码从Form表单获取▶️, 组合一下即可
js定义对象

<template><div><!--增加按钮和搜索框--><div style="margin: 10px 5px"><!--解读1.@click="add" 表示点击新增, 就会触发add方法--><el-button type="primary" @click="add">新增</el-button><el-button>其它</el-button></div><!--margin: 顶部距离 左侧距离--><div style="margin: 10px 5px"><el-input v-model="search" style="width: 20%" placeholder="请输入家居名"/><el-button style="margin: 10px" type="primary">查询</el-button></div><el-table :data="tableData" stripe style="width: 90%"><el-table-column sortable prop="date" label="日期"/><el-table-column prop="name" label="名字"/><el-table-column prop="address" label="地址"/><el-table-column fixed="right" label="操作" width="120"><template #default><el-button link type="primary">编辑</el-button><el-button link type="primary">删除</el-button></template></el-table-column></el-table><!--说明家居的弹窗说明:1.el-dialog v-model="dialogFormVisible" 表示对话框, 和 dialogFormVisible 变量双向绑定, 控制是否显示对话框2.el-form :model="form" 表示 表单数据 和 form数据变量 双向绑定3.el-input v-model="form.name" 表示表单的input控件, 名字为name, 需要和后台JavaBean属性一致4.在前端中, 对象的属性是可以动态生成的. 这个知识点, 我们在讲解前端技术栈讲过.--><el-dialog v-model="dialogVisible" title="提示" width="500"><el-form :model="form" label-width="120px"><el-form-item label="家居名"><el-input v-model="form.name" style="width: 80%"/></el-form-item><el-form-item label="厂商"><el-input v-model="form.marker" style="width: 80%"/></el-form-item><el-form-item label="价格"><el-input v-model="form.price" style="width: 80%"/></el-form-item><el-form-item label="销量"><el-input v-model="form.sales" style="width: 80%"/></el-form-item><el-form-item label="库存"><el-input v-model="form.stock" style="width: 80%"/></el-form-item></el-form><template #footer><div class="dialog-footer"><el-button @click="dialogVisible = false">取 消</el-button><el-button type="primary" @click="save">确 定</el-button></div></template></el-dialog></div>
</template><script>
// @ is an alias to /src
// 导出组件
export default {name: 'HomeView',components: {},data() {return {search: '',dialogVisible: false,form: {},//定义一个空表单}},methods: {add() {//显示对话框this.dialogVisible = true;//情况添加表单数据this.form = {}}}
}
</script>

7.完成测试, 点击新增按钮, 看看能否正常的弹出添加家居的对话框(含有表单).在这里插入图片描述

8.项目前端: 安装axios, 用于发送Ajax请求给后台
npm i axios -S

9.创建工具文件 D:\idea_project\SSM-Vue整合项目\ssm_vue\src\utils\request.js

//引入axios包
//重要提示: 如果在启动前端项目时, 提示找不到axios, 把光标放在 import axios from "axios"的'axios', 会有一个修复提示, 导入axios, 导入即可正常使用.
import axios from "axios";
//通过axios创建对象-request对象, 用于发送请求到后端
const request = axios.create({timeout: 5000
})//request拦截器的处理
//1.可以对请求做统一的处理
//2.比如统一地假如token, Content-Type等
request.interceptors.request.use(config => {config.headers['Content-Type'] = "application/json;charset=utf-8";return config;
}, error => {return Promise.reject(error);
})//导出request对象, 在其它文件引入就可以使用
export default request;

10.修改HomeView.vue, 在methods编写save方法, 并测试, 会出现跨域问题.
发送axios请求

<script>
// @ is an alias to /src
//导入request对象
import request from "@/utils/request";//导出组件
export default {name: 'HomeView',components: {},methods: {save() {//将填写的表单数据,发送给后端//解读//1.url: http://localhost:8080/ssm/save//2.this.form: 携带的数据request.post("http://localhost:8080/ssm/save", this.form).then(res => {console.log("res=", res);console.log("res.data=", res.data);this.dialogVisible = false;})}}
}
</script>

在这里插入图片描述

11.修改D:\idea_project\SSM-Vue整合项目\ssm_vue\vue.config.js, 解决跨域问题.
因为修改了配置文件, npm serve 需要重启, 否则不能识别.

module.exports = {devServer: {port: 10000,                  //前端vue启动端口//解读:如果我们请求的地址 /api/save => 代理到 http://localhost:8080/ssm/saveproxy: {                      //设置代理, 必须填'/api': {                   //设置拦截器, 拦截器格式 斜杠+拦截器名字, 名字可以自己定target: 'http://localhost:8080/ssm', //代理的目标地址, 就是/api 代理 http://localhost:8080/ssmchangeOrigin: true,               //是否设置同源, 输入是的, 浏览器就允许跨域pathRewrite: {                    //路径重写'/api':''                       //选择忽略拦截器里面的单词}}}}
}

12.老师提醒, 这里容易出现的问题
1)一定要确定 request.post(“/api/save”) 被代理后的url, 是项目后台服务对应提供的API接口.

2)跨域执行请求时, 如果报错, 浏览器还是提示http://localhost:10000/api/xxx, 所以不要认为是api没有替换你的配置.

注意事项和细节

1.Postman测试时, 要制定Content-Type, 否则会报错在这里插入图片描述

2.如果需要将提交的json数据, 封装到对应的JaveBean, 需要配置@RequestBody, 否则会报错500.在这里插入图片描述

如果需要返回json数据, 需要在方法上, 配置@ResponseBody, 否则会报错404.在这里插入图片描述

实现功能04-显示家居信息

需求分析/图解

在这里插入图片描述

思路分析

1.完成后台代码从dao -> service ->controller, 并对每层代码进行测试.

2.完成前台代码, 使用axios发送http请求, 返回所有家居数据, 将数据绑定显示.

代码实现

1.修改FurnService.javaFurnServiceImpl.java, 增加findAll方法

//查询所有的家居信息
public List<Furn> findAll();
@Override
public List<Furn> findAll() {//查看分析FurnMapper.xml文件//传入是null, 表示返回所有的家居信息return furnMapper.selectByExample(null);
}

2.修改FurnServiceTest.java, 测试find All方法.

@Test
public void findAll() {List<Furn> furns = furnService.findAll();for (Furn furn : furns) {System.out.println("furn--" + furn);}
}

3.修改FurnController.java, 处理修改请求, 并使用Postman完成测试.

/*** 响应客户的查询请求* @param furn* @return*/
@GetMapping("/furns")
@ResponseBody
public Msg listFurns() {List<Furn> furns = furnService.findAll();;没有抛出异常, 就返回成功信息//Msg msg = Msg.success();把家居信息, 封装到msg对象//return msg.add("furns", furns);return Msg.success().add("furns", furns);
}

在这里插入图片描述

4.修改HomeView.vue, 编写list方法. vue生命周期
1)修改 el-table

<el-table :data="tableData" stripe style="width: 90%"><el-table-column sortable prop="id" v-model="tableData.id"/><el-table-column prop="name" v-model="tableData.name" label="家居名"/><el-table-column prop="maker" v-model="tableData.maker" label="厂商"/><el-table-column prop="sales" v-model="tableData.sales" label="销量"/><el-table-column prop="price" v-model="tableData.price" label="价格"/><el-table-column prop="stock" v-model="tableData.stock" label="库存"/><el-table-column fixed="right" label="操作" width="120"><template #default><el-button link type="primary">编辑</el-button><el-button link type="primary">删除</el-button></template></el-table-column>
</el-table>

2)修改 tableData: []

data() {return {search: '',dialogVisible: false,form: {},//定义一个空表单tableData: []}
},

3)在created() 调用list() 完成页面数据获取

methods: {save() {//将填写的表单数据,发送给后端//解读//1.url: http://localhost:8080/ssm/save//2.this.form: 携带的数据request.post("/api/save", this.form).then(res => {console.log("res=", res);console.log("res.data=", res.data);this.dialogVisible = false;//调用list方法, 刷新数据this.list();})},//编写list方法, 请求返回家居信息//list方法应该是自动调用list() {request.get("/api/furns").then(res => {console.log("res.data--", res.data);//解读: 为什么是res.data.extend.furns, 可以根据console输出的数据结构来查看this.tableData = res.data.extend.furns;})}
},
created() {//生命周期函数this.list();//调用list方法
}

5.完成测试, 看看是否可以显示家居列表信息在这里插入图片描述

6.修改src/utils/request.js, 增加response拦截器, 统一处理响应后结果
字符串转JSON

//可以在调用接口响应后, 统一地处理返回结果
request.interceptors.response.use(response => {let res = response.data;//如果返回的是文件if (response.config.responseType === 'blob') {return res;}//如果是string, 就转成jsonif (typeof res === 'string') {//如果res 不为'', 就转换成json对象res = res ? JSON.parse(res) : res;}return res;
}, error => {console.log("error=", error);return Promise.reject(error);
})

7.修改HomeView.vue, 简化返回处理

list() {request.get("/api/furns").then(res => {console.log("res--", res);//解读: 为什么是res.data.extend.furns, 可以根据console输出的数据结构来查看//因为我们对返回response结果进行了统一拦截处理 let res = response.data;//, 所以我们这里直接使用 res.extend.furnsthis.tableData = res.extend.furns;})
}

8.完成测试在这里插入图片描述

实现功能05-修改家居信息

需求分析/图解

在这里插入图片描述在这里插入图片描述

思路分析

1.完成后台代码从 dao ->service -> controller, 并对每层代码进行测试

2.完成前台代码, 回显家居信息, 再使用axios发送http请求, 更新数据, 将数据绑定显示.

代码实现

1.修改FurnService.javaFurnServiceImpl.java, 增加update方法

//修改家居
public void update(Furn furn);
@Override
public void update(Furn furn) {furnMapper.updateByPrimaryKeySelective(furn);
}

2.修改FurnServiceTest.java, 测试update方法.

@Test
public void update() {Furn furn = new Furn();furn.setId(18);furn.setName("大象家居");furn.setMaker("大象传人");//因为imgPath属性有一个默认值, 所以如果我们不希望生成的update语句对img_path字段修改, 就显示地设置nullfurn.setImgPath(null);furnService.update(furn);System.out.println("修改成功");
}

3.修改FurnController.java, 处理修改请求, 并使用Postman完成测试.
rest请求风格

/*** 1.响应客户端的修改请求* @param furn* @return*/
@PutMapping("/update")
@ResponseBody
public Msg update(@RequestBody Furn furn) {furnService.update(furn);//没有抛出异常, 就返回成功信息Msg success = Msg.success();return success;
}

在这里插入图片描述

4.修改HomeView.vue, 编写handleEdit方法, 回显数据 并测试.

<el-table-column fixed="right" label="操作" width="120"><!--说明1.这里通过 handleEdit(scope.row)2.可以将当前行数据传递给 handleEdit--><template #default="scope"><el-button link type="primary" @click="handleEdit(scope.row)">编辑</el-button><el-button link type="primary">删除</el-button></template>
</el-table-column>
methods: {handleEdit(row) {//console.log("row--", row);//将当前的家居信息绑定到弹出对话框的表单上//1. 方式1: 可以通过row.id 到后端-DB去获取对应的家居信息, 返回后将其绑定到this.form[小伙伴自己思考解决]//2. 方式2: 把获取的row的数据通过处理, 绑定到this.form 进行显示//3. JSON.stringify(row): 将row 转成json字符串//4. JSON.parse(JSON.stringify(row)) 将json字符串 转成json对象this.form = JSON.parse(JSON.stringify(row));//显示对话框this.dialogVisible = true;}
}

在这里插入图片描述在这里插入图片描述

5.修改HomeView.vue, 修改save方法, 处理修改请求, 添加 更新成功的消息框, 不需要做额外处理

save() {//将填写的表单数据,发送给后端//修改和添加时走的同一个方法if (this.form.id) {//表示修改request.put("/api/update", this.form).then(res => {// console.log("res=", res);if (res.code === 200) {//修改成功//提示一个成功的消息框this.$message({message: "修改成功",type: "success",});} else {this.$message({message: "修改失败",type: "error",});}//关闭对话框this.dialogVisible = false;//调用list方法, 刷新数据this.list();})} else {//表示添加//解读//1.url: http://localhost:8080/ssm/save//2.this.form: 携带的数据request.post("/api/save", this.form).then(res => {// console.log("res=", res);this.dialogVisible = false;//调用list方法, 刷新数据this.list();});}//这里有一个注意事项...
},

注意事项和细节

1.<template #default="scope">
在这里插入图片描述

2.调用list() 刷新数据需要注意的地方. 这样写是错误的, axios本质是ajax请求, 异步处理机制.

save() {//将填写的表单数据,发送给后端//修改和添加时走的同一个方法if (this.form.id) {//表示修改//本质发出ajax请求-异步处理request.put("/api/update", this.form).then(res => {// console.log("res=", res);if (res.code === 200) {//修改成功//提示一个成功的消息框this.$message({message: "修改成功",type: "success",});} else {this.$message({message: "修改失败",type: "error",});}})} else {//表示添加//解读//1.url: http://localhost:8080/ssm/save//2.this.form: 携带的数据request.post("/api/save", this.form).then(res => {// console.log("res=", res);});}//关闭对话框this.dialogVisible = false;//调用list方法, 刷新数据this.list();//这里有一个注意事项...
},

实现功能06-删除家居信息

需求分析/图解

思路分析

在这里插入图片描述

代码实现

1.修改FurnService.javaFurnServiceImpl.java, 增加del方法

//删除家居
public void del(Integer id);
@Override
public void del(Integer id) {furnMapper.deleteByPrimaryKey(id);
}

2.修改FurnServiceTest.java, 测试del方法.

@Test
public void del() {furnService.del(22);System.out.println("删除成功");
}

3.修改FurnController.java, 处理修改请求, 并使用Postman完成测试.
URL占位符

/*** 1.响应客户端的删除请求* @param furn* @return*/
@DeleteMapping("/del/{id}")
@ResponseBody
public Msg del(@PathVariable("id") Integer id) {furnService.del(id);//没有抛出异常, 就返回成功信息Msg success = Msg.success();return success;
}

在这里插入图片描述

4.修改HomeView.vue, 编写handleDel方法, 完成删除 并测试.

<el-table-column fixed="right" label="操作" width="120"><!--说明1.这里通过 handleEdit(scope.row)2.可以将当前行数据传递给 handleEdit--><template #default="scope"><el-button type="text" @click="handleEdit(scope.row)">编辑</el-button><!--说明1.如果你点击的是确定, 就会触发handleDel2.如果你点击的是取消, 就不会触发handleDel--><el-popconfirm title="确定要删除吗?" @confirm="handleDel(scope.row.id)"><template #reference><el-button size="small" type="danger">删除</el-button></template></el-popconfirm></template>
</el-table-column><el-table-column fixed="right" label="操作" width="120"><!--说明1.这里通过 handleEdit(scope.row)2.可以将当前行数据传递给 handleEdit--><template #default="scope"><el-button type="text" @click="handleEdit(scope.row)">编辑</el-button><!--说明1.如果你点击的是确定, 就会触发handleDel2.如果你点击的是取消, 就不会触发handleDel--><el-popconfirm title="确定要删除吗?" @confirm="handleDel(scope.row.id)"><template #reference><el-button size="small" type="danger">删除</el-button></template></el-popconfirm></template>
</el-table-column>
handleDel(id) {console.log("id=", id);request.delete('/api/del/' + id).then(res => {if (res.code === 200) {//删除成功this.$message({message: res.msg,type: "success",});} else {//删除失败this.$message({message: res.msg,type: "error",});}//调用list方法, 刷新数据this.list();})
},

在这里插入图片描述在这里插入图片描述

课后作业

1.把前面我们实现的 Vue+SSM 各个功能, 自己写一遍.
- 一定要自己写一遍, 否则没有印象, 理解不会深入.
- 如果出现问题, 一定是代码问题, 要静下心来, 认真排查, 要逐步锻炼自己的排错能力.

2.修改家居信息功能, 回显家居表单数据, 改成从后端-DB获取

●代码实现
1.修改FurnService.javaFurnServiceImpl.java, 增加findFurnById方法

//根据id查询家居信息
public Furn findFurnById(Integer id);
@Override
public Furn findFurnById(Integer id) {return furnMapper.selectByPrimaryKey(id);
}

2.修改FurnServiceTest.java, 测试findFurnById方法.

@Test
public void findFurnById() {Furn furn = furnService.findFurnById(7);System.out.println("furn--" + furn);
}

3.修改FurnController.java, 处理修改请求, 并使用Postman完成测试.

/*** 1.响应客户端的查询请求* @param furn* @return*/
@GetMapping("/findFurnById/{id}")
@ResponseBody
public Msg findFurnById(@PathVariable("id") Integer id) {Furn furn = furnService.findFurnById(id);//没有抛出异常, 就返回成功信息return Msg.success().add("furn", furn);
}

在这里插入图片描述

4.修改HomeView.vue, 编写handleEdit方法, 并测试.

handleEdit(row) {// console.log("row--", row);//将当前的家居信息绑定到弹出对话框的表单上//1. 方式1: 可以通过row.id 到后端-DB去获取对应的家居信息, 返回后将其绑定到this.form[小伙伴自己思考解决]request.get('/api/findFurnById/' + row.id).then(res => {this.form = res.extend.furn;})//2. 方式2: 把获取的row的数据通过处理, 绑定到this.form 进行显示//3. JSON.stringify(row): 将row 转成json字符串//4. JSON.parse(JSON.stringify(row)) 将json字符串 转成json对象// this.form = JSON.parse(JSON.stringify(row));//显示对话框this.dialogVisible = true;
},

在这里插入图片描述

实现功能07-分页显示列表

需求分析/图解

在这里插入图片描述

思路分析

1.后台使用MyBatis PageHelper插件完成分页查询.前端使用分页组件.

2.修改FurnController, 增加处理分页显示代码 API/接口

3.完成前台代码, 加入分页导航, 并将分页请求和后台接口结合.

4.简单回顾JavaWeb原生项目的分页模型. 说明: 有了MyBatis PageHelper和前端的分页组件, 完成分页就非常的方便, 但是底层的分页模型和前面我们的java web原生项目一样.

代码实现

1.修改pom.xml, 加入分页插件

<!--引入mybatis pageHelper分页插件-->
<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>5.2.1</version>
</dependency>

2.修改mybatis-config.xml, 配置分页拦截器

<!--说明
1.plugins标签需要放在typeAliases标签后, 是DOCTYPE约束的
2.配置分页拦截器
-->
<plugins><plugin interceptor="com.github.pagehelper.PageInterceptor"><!--解读配置分页合理化1.如果用户请求的pageNum > pages, 就显示查询最后一页2.如果用户请求的pageNum < 0, 就显示查询第一页--><property name="reasonable" value="true"/></plugin>
</plugins>

3.修改FurnController.java, 增加分页查询处理

/*** 分页请求接口** @param pageNum:  要显示第几页, 默认为1* @param pageSize: 每页要显示几条记录, 默认为5* @return*/
@RequestMapping("/furnsByPage")
@ResponseBody
public Msg listFurnsByPage(@RequestParam(defaultValue = "1") Integer pageNum,@RequestParam(defaultValue = "5") Integer pageSize) {//设置分页参数//解读//1.调用findAll完成查询, 底层会进行物理分页, 而不是逻辑分页//2.会根据分页参数来计算 limit ?, ?, 在发出sql语句时, 会带limit//3.我们后面会给大家抓取SQLPageHelper.startPage(pageNum, pageSize);List<Furn> furns = furnService.findAll();//将分页查询的结果, 封装到PageInfo//PageInfo 对象包含了分页的各个信息, 比如当前页面pageNum, 共有多少记录PageInfo pageInfo = new PageInfo(furns, pageSize);//将pageInfo封装到Msg对象, 返回return Msg.success().add("pageInfo", pageInfo);
}

4.使用Postman进行测试, 看看分页查询是否OK
在这里插入图片描述

数据包含在了list属性里

在这里插入图片描述在这里插入图片描述

5.修改HomeView.vue, 完成分页导航显示, 分页请求. 给标签属性绑定值

1)添加分页导航控件

<div style="margin: 10px 0px"><el-pagination@size-change="handleSizeChange"@current-change="handleCurrentChange"v-bind:current-page="currentPage"v-bind:page-sizes="[5, 10]"v-bind:page-size="pageSize"layout="total, sizes, prev, pager, next, jumper"v-bind:total="total"></el-pagination>
</div>

2)增加分页初始化数据

data() {return {//增加分页相应的数据绑定currentPage: 1,//当前页pageSize: 5,//每页显示记录数total: 10,//共有多少记录}
}

3)修改list方法, 换成分页请求数据的接口

list() {//请求分页的接口request.get("/api/furnsByPage", {params: {//指定请求携带的参数pageNum: this.currentPage,pageSize: this.pageSize,}}).then(res => {//处理返回的分页信息this.tableData = res.extend.pageInfo.list;this.total = res.extend.pageInfo.total;})
},

4)处理当前页变化, 比如点击分页链接, 或者go to 第几页

handleCurrentChange(pageNum) {//处理分页请求//当用户点击分页超链接时, 会携带pageNum// console.log("pageNum=", pageNum);this.currentPage = pageNum;//发出请求this.list();
},

5)处理每页显示多少条记录变化

handleSizeChange(pageSize) {this.pageSize = pageSize;//发出请求this.list();
},

完成测试

在这里插入图片描述

实现功能08-带条件查询分页显示列表

需求分析/图解

在这里插入图片描述

思路分析

1.完成后台代码从 dao ->service -> controller, 并对每层代码进行测试

2.完成前台代码, 使用axios发送http请求, 完成带条件查询分页显示

代码实现

1.修改FurnService.javaFurnServiceImpl.java, 增加条件查询

//根据家居名查询家居信息
public List<Furn> findByCondition(String name);
@Override
public List<Furn> findByCondition(String name) {FurnExample furnExample = new FurnExample();//通过criteria 对象可以设置查询条件FurnExample.Criteria criteria = furnExample.createCriteria();//判断name是否有具体的内容if (StringUtils.hasText(name)) {criteria.andNameLike("%" + name + "%");}//说明: 如果没有传值, 即为null, "", "   "时, 依然是查询所有的记录return furnMapper.selectByExample(furnExample);
}

2.修改FurnServiceTest.java, 测试findByCondition方法.

@Test
public void findByCondition() {List<Furn> furns = furnService.findByCondition("风格");for (Furn furn : furns) {System.out.println("furn--" + furn);}
}

3.修改FurnController.java, 处理带条件分页查询, 并使用Postman完成测试.

/*** 根据家居名进行分页查询-带条件** @param pageNum* @param pageSize* @return*/
@RequestMapping("/furnsByConditionPage")
@ResponseBody
public Msg listFurnsByCondition(@RequestParam(defaultValue = "1") Integer pageNum,@RequestParam(defaultValue = "5") Integer pageSize,@RequestParam(defaultValue = "") String search) {//设置分页参数//解读//1.调用findAll完成查询, 底层会进行物理分页, 而不是逻辑分页//2.会根据分页参数来计算 limit ?, ?, 在发出sql语句时, 会带limit//3.我们后面会给大家抓取SQLPageHelper.startPage(pageNum, pageSize);List<Furn> furns = furnService.findByCondition(search);//将分页查询的结果, 封装到PageInfo//PageInfo 对象包含了分页的各个信息, 比如当前页面pageNum, 共有多少记录PageInfo pageInfo = new PageInfo(furns, pageSize);//将pageInfo封装到Msg对象, 返回return Msg.success().add("pageInfo", pageInfo);
}

在这里插入图片描述

4.修改HomeView.vue

<!--margin: 顶部距离 左侧距离-->
<div style="margin: 10px 5px"><el-input v-model="search" style="width: 20%" placeholder="请输入家居名"/><el-button style="margin: 10px" type="primary" @click="list">检索</el-button>
</div>

数据池

data() {return {search: '',//检索条件, 可以在进行分页时保留上次的检索条件}
},

list方法

list() {//请求分页的接口-带检索条件request.get("/api/furnsByConditionPage", {params: {//指定请求携带的参数pageNum: this.currentPage,pageSize: this.pageSize,search: this.search,}}).then(res => {//处理返回的分页信息this.tableData = res.extend.pageInfo.list;this.total = res.extend.pageInfo.total;})
},

5.测试
在这里插入图片描述

实现功能09-添加家居表单前端校验

需求分析/图解

在这里插入图片描述

在这里插入图片描述

说明: 参考 element-plus 表单验证

思路分析

1.完成前台代码, 使用ElementPlus的表单 rules 验证即可

2.参考element-plus 表单验证文档

代码实现

1.修改HomeView.vue, 增加表单验证处理代码. 验证数字
增加对表单各个字段的校验规则

data() {return {//定义添加表单校验规则rules: {name: [//这里我们可以写多个针对name属性的校验规则{required: true, message: "请输入家居名", trigger: "blur"}],maker: [//这里我们可以写多个针对maker属性的校验规则{required: true, message: "请输入厂商", trigger: "blur"}],price: [//这里我们可以写多个针对price属性的校验规则{required: true, message: "请输入价格", trigger: "blur"},//使用正则表达式对输入的数据进行校验{pattern: /^([1-9]\d*|0)(\.\d+)?$/, message: "请输入数字", trigger: "blur"}],sales: [//这里我们可以写多个针对sales属性的校验规则{required: true, message: "请输入销量", trigger: "blur"},{pattern: /^([1-9]\d*|0)$/, message: "请输入数字", trigger: "blur"}],stock: [//这里我们可以写多个针对stock属性的校验规则{required: true, message: "请输入库存", trigger: "blur"},{pattern: /^([1-9]\d*|0)$/, message: "请输入数字", trigger: "blur"}],}}
},

指定将创建的规则引用到form表单, 注意名称要对应
在这里插入图片描述

2.测试, 就可以看到验证规则生效了. 是光标离开输出框时, 出现检验效果, 因为是trigger: "blur"事件, 但是用户提交还是能成.

3.修改HomeView.vue, 但表单验证不通过时, 不提交表单
修改save方法

save() {//将填写的表单数据,发送给后端//修改和添加时走的同一个方法if (this.form.id) {//表示修改//本质发出ajax请求-异步处理//...} else {//表示添加//表单验证是否通过this.$refs['form'].validate(valid => {//valid就是表单校验后返回的结果if (valid) {//如果校验通过//解读//1.url: http://localhost:8080/ssm/save//2.this.form: 携带的数据request.post("/api/save", this.form).then(res => {// console.log("res=", res);//关闭对话框this.dialogVisible = false;//调用list方法, 刷新数据this.list();});} else {//校验没有通过this.$message({type: "error",message: "表单校验失败, 不提交"})return false;//放弃提交}})}//这里有一个注意事项...
},

修改add方法

add() {//显示添加对话框-带表单//显示对话框this.dialogVisible = true;//情况添加表单数据this.form = {};//清空上次校验的信息this.$refs['form'].resetFields();
},

在这里插入图片描述

实现功能10-添加家居表单后端校验

需求分析/图解

1.为什么前端校验了, 后端还需要校验? -使用Postman添加数据, 打破前端校验机制
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

2.后端校验-需求分析, 但后端校验没有通过, 会出现灰色框提示, 后台不真正入库数据在这里插入图片描述

思路分析

1.后台 使用JSR303数据校验, 引入hibernate-validator.jar, 学习SpringMVC JSR303校验时遇到过.

2.前端 使用ElementPlus进行数据绑定, 并显示错误信息

代码实现

1.修改pom.xml, 引入hibernate-validator jar文件

<!--JSR303数据校验支持引入hibernate-validator-->
<dependency><groupId>org.hibernate</groupId><artifactId>hibernate-validator</artifactId><version>6.1.1.Final</version>
</dependency>

2.修改Furn.java, 使用hibernate-validator

@NotEmpty(message = "请输入家居名")
private String name;@NotEmpty(message = "请输入厂商")
private String maker;@NotNull(message = "请输入数字")
@Range(min = 0, message = "价格不能小于0")
private BigDecimal price;@NotNull(message = "请输入数字")
@Range(min = 0, message = "销量不能小于0")
private Integer sales;@NotNull(message = "请输入数字")
@Range(min = 0, message = "库存不能小于0")
private Integer stock;

3.修改FurnController.java, 处理带条件分页查询, 并使用Postman完成测试.

@PostMapping("/save")
@ResponseBody
public Msg save(@Validated @RequestBody Furn furn, Errors errors) {Map<String, Object> map = new HashMap<>();List<FieldError> fieldErrors = errors.getFieldErrors();for (FieldError fieldError : fieldErrors) {map.put(fieldError.getField(), fieldError.getDefaultMessage());}if (map.isEmpty()) {//说明后端校验通过, 因为没有发现校验错误furnService.save(furn);//没有抛出异常, 就返回成功信息Msg success = Msg.success();return success;} else {//校验失败, 就把错误信息封装到Msg对象, 并返回return Msg.fail().add("errors", map);}
}

在这里插入图片描述在这里插入图片描述在这里插入图片描述
4.修改HomeView.vue, 显示服务器校验返回的提示信息
在数据池, 增加显示错误信息的变量

data() {return {//存放后端校验的错误信息serverValidErrors: {},}
},

修改save方法, 显示错误提示

if (valid) {//如果校验通过//解读//1.url: http://localhost:8080/ssm/save//2.this.form: 携带的数据request.post("/api/save", this.form).then(res => {console.log("res=", res);if (res.code === 200) {//添加成功//关闭对话框this.dialogVisible = false;//调用list方法, 刷新数据this.list();} else {//后端校验失败//取出校验失败的信息, 赋给serverValidErrorsthis.serverValidErrors.name = res.extend.errors.name;this.serverValidErrors.maker = res.extend.errors.maker;this.serverValidErrors.price = res.extend.errors.price;this.serverValidErrors.sales = res.extend.errors.sales;this.serverValidErrors.stock = res.extend.errors.stock;}});
}

修改对话框, 显示后台返回的校验错误信息

<el-form ref="form" :model="form" :rules="rules" label-width="120px" style="width: 80%"><el-form-item label="家居名" prop="name"><el-input v-model="form.name" style="width: 50%"/>{{serverValidErrors.name}}</el-form-item><el-form-item label="厂商" prop="maker"><el-input v-model="form.maker" style="width: 50%"/>{{serverValidErrors.maker}}</el-form-item><el-form-item label="价格" prop="price"><el-input v-model="form.price" style="width: 50%"/>{{serverValidErrors.price}}</el-form-item><el-form-item label="销量" prop="sales"><el-input v-model="form.sales" style="width: 50%"/>{{serverValidErrors.sales}}</el-form-item><el-form-item label="库存" prop="stock"><el-input v-model="form.stock" style="width: 50%"/>{{serverValidErrors.stock}}</el-form-item>
</el-form>

为了触发后端校验, 先把前端校验解除

} else {//表示添加//表单验证是否通过this.$refs['form'].validate(valid => {//这里我们让前端校验放行, 测试后端校验的效果, 测试完毕, 再改回来valid = true;//valid就是表单校验后返回的结果if (valid) {//如果校验通过

测试
在这里插入图片描述

修改add()方法, 清空错误信息

add() {//显示添加对话框-带表单//显示对话框this.dialogVisible = true;//情况添加表单数据this.form = {};//清空上次前端校验的信息this.$refs['form'].resetFields();//清空上次后端校验的信息this.serverValidErrors = {};
},

SSM项目[前后端分离]小结+作业要求

●说明: 前后端分离开发, 前端框架Vue + 后端框架SSM

1.前端框架Vue

2.后端框架-SSM (Spring + SpringMVC + MyBatis)

3.数据库-MySQL

4.项目的依赖管理-Maven

5.分页-pagehelper

6.逆向工程-MyBatis Generator

7.其它…


●前端框架Vue
1.使用了ElementPlus来展示数据
2.使用Axios对象来请求数据 / 接口

●后端框架SSM
1.使用了经典的三层结构
2.使用MyBatis Generator 和 MyBatis pageHelper

●作业
1.把我们写的项目. 小伙伴可以独立地完整地写出来.
2.一定要自己写, 培养自己独立解决问题的能力, 并且提高解决Bug能力
3.逐步形成自己的编程套路 / 思路.
4.前端这块可以展示就可以了, 不需要写的非常好看, 关键是梳理清楚前后端数据通信机制. 多写, 多总结, 多梳理, 形成自己的知识.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/704180.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

文心一言 VS 讯飞星火 VS chatgpt (252)-- 算法导论18.2 5题

五、因为叶结点无需指向孩子结点的指针&#xff0c;那么对同样大小的磁盘页面&#xff0c;可选用一个与内部结点不同的(更大的) t 值。请说明如何修改 B 树的创建和插人过程来处理这个变化。如果要写代码&#xff0c;请用go语言。 文心一言&#xff1a; 当我们在B树&#xff…

物联网设计竞赛_5_Jetson Nano连接摄像头解决运行卡顿问题

我在命令行用camorama命令打开摄像头的时候发现摄像头非常流畅 当我用python的cv2库打开摄像头的时候发现摄像头显示图片异常卡顿&#xff0c;在网上多方寻觅无果后&#xff0c;经过偶然尝试&#xff0c;我发现了卡顿原来是视频帧率问题 淘宝官方资料看我的摄像头只有30fps, …

84.网络游戏逆向分析与漏洞攻防-游戏技能系统分析-筛选与技能有关的数据包

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 如果看不懂、不知道现在做的什么&#xff0c;那就跟着做完看效果&#xff0c;代码看不懂是正常的&#xff0c;只要会抄就行&#xff0c;抄着抄着就能懂了 内容…

C++动态内存区域划分、new、delete关键字、泛型编程、函数模版、类模版

目录 一、C/C中程序的内存区域划分 为什么会存在内存区域划分&#xff1f; 二、new关键字 1、内置类型的new/delete使用方法&#xff1a; 2、new和delete的本质 3、常见面试题——malloc/free和new/delete的区别 三、模版 1、泛型编程 2、函数模版 &#xff08;1&…

XMind 头脑风暴/思维导图软件_V24.04.10291 PC高级版

一款风靡全球的头脑风暴和思维导图软件&#xff0c;为激发灵感和创意而生。在国内使用广泛&#xff0c;拥有强大的功能&#xff0c;包括思维管理&#xff0c;商务演示&#xff0c;与办公软件协同工作等功能。XMind中文版采用全球先进的Eclipse RCP软件架构&#xff0c;是集思维…

python:SunMoonTimeCalculator

# encoding: utf-8 # 版权所有 2024 ©涂聚文有限公司 # 许可信息查看&#xff1a; # 描述&#xff1a; https://github.com/Broham/suncalcPy # Author : geovindu,Geovin Du 涂聚文. # IDE : PyCharm 2023.1 python 3.11 # Datetime : 2024/5/14 21:59 # User …

百面算法工程师 | YOLOv6面试考点原理全解析

本文给大家带来的百面算法工程师是深度学习目标检测YOLOv6面试总结&#xff0c;文章内总结了常见的提问问题&#xff0c;旨在为广大学子模拟出更贴合实际的面试问答场景。在这篇文章中&#xff0c;我们还将介绍一些常见的深度学习目标检测面试问题&#xff0c;并提供参考的回答…

【练习】分治--快排思想

&#x1f3a5; 个人主页&#xff1a;Dikz12&#x1f525;个人专栏&#xff1a;算法(Java)&#x1f4d5;格言&#xff1a;吾愚多不敏&#xff0c;而愿加学欢迎大家&#x1f44d;点赞✍评论⭐收藏 目录 颜色分类 题目描述 题解 代码实现 排序数组 题目描述 题解 代码…

Shell之常用命令

目录 1.排序工具--sort命令 1.1 快读查找一个目录中最大文件 2.去重工具--uniq命令 2.1 分析判断远程登录错误次数&#xff0c;禁止该用户远程登录 3.修改工具--tr命令 4.列截取工具--cut命令 5.分割文件工具--split命令 6.合并文件列--paste命令 7.扫描工具--eval命令…

YOLOv8改进教程|加入可改变核卷积AKConv模块,效果远超DSConv!

⭐⭐ YOLOv8改进专栏|包含主干、模块、注意力机制、检测头等前沿创新 ​ ⭐⭐ 一、 论文介绍 论文链接&#xff1a;https://arxiv.org/abs/2311.11587 代码链接&#xff1a;GitHub - CV-ZhangXin/AKConv 论文速览&#xff1a;&#xff1a;AKConv是2023年11月发表的一种可变卷积…

mobarxtem应用与华为设备端口绑定技术

交换机端口绑定 华为交换机的基础配置与MOBAXTERM终端连接 实验步骤&#xff1a; 一、给每个交换机划分vlan并添加端口 1.单个vlan的划分 2.批量划分vlan 在高端交换机CE6800上批量划分连续编号的VLAN&#xff0c;本例中连续的vlan20到vlan25 [~CE6800]vlan b 20 to 25 3…

Django视图Views

Views视图 HttpRequest 和HttpResponse Django中的视图主要用来接受web请求&#xff0c;并做出响应。视图的本质就是一个Python中的函数视图的响应分为两大类 1)以Json数据形式返回(JsonResponse) 2)以网页的形式返回 2.1)重定向到另一个网页 (HttpRe…