SSM–功能实现
实现功能04-添加家居信息
需求分析/图解
思路分析
- 1.完成后台代码从dao -> serivce -> controller , 并对每层代码进行测试, 到controller 这一层,使用Postman 发送http post 请求完成测试
- 2.完成前端代码, 使用axios 发送ajax(json 数据)给后台, 实现添加家居信息
代码实现
- 创建src\main\java\com\nlc\furns\service\FurnService.java 和src\main\java\com\nlc\furns\service\FurnServiceImpl.java, 增加添加方法
public interface FurnService { public void save(Furn furn); }
@Service public class FurnServiceImpl implements FurnService { //注入/装配FurnMapper接口对象(代理对象) @Resource private FurnMapper furnMapper; @Override public void save(Furn furn) { //解读 //1. 使用insertSelective //2. 因为我们的furn表的id是自增的,就使用insertSelective furnMapper.insertSelective(furn); }
修改Furn.java , 当创建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; if(!(imgPath == null || imgPath.equals("")) ){ this.imgPath = imgPath; }
- 创建ssm_vue\ssm\ssm\src\test\java\com\nlc\furns\service\FurnServiceTest.java ,测试方法
public class FurnServiceTest { //属性 private ApplicationContext ioc; //从spring容器中,获取的是FurnService接口对象/代理对象 private FurnService furnService; @Before public void init() { ioc = new ClassPathXmlApplicationContext("applicationContext.xml"); //说明 //1. 通过FurnService.class 类型获取 FurnService接口对象/代理对象 furnService = ioc.getBean(FurnService.class); //com.sun.proxy.$Proxy21 System.out.println("furnService-" + furnService.getClass()); } @Test public void save() { Furn furn = new Furn(null, "小风扇", "顺平家居", new BigDecimal(180), 10, 70, "assets/images/product-image/1.jpg"); furnService.save(furn); System.out.println("添加成功~"); }
- 创建ssm_vue\ssm\ssm\src\main\java\com\nlc\furns\bean\Msg.java用来返回json 的数据的通用类
// Msg: 后端程序返回给前端的json数据的Msg对象=》本质就是数据规则 public class Msg { //状态码 200-成功 400-失败 private int code; //信息-说明 private String msg; //返回给客户端/浏览器的数据-Map集合 private Map<String, Object> extend = new HashMap<>(); //编写几个常用的方法-封装好msg //返回success对应的msg public static Msg success() { Msg msg = new Msg(); msg.setCode(200); msg.setMsg("success"); return msg; } //返回fail对应的msg public 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; } public int getCode() { return code; } public void setCode(int code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public Map<String, Object> getExtend() { return extend; } public void setExtend(Map<String, Object> extend) { this.extend = extend; } }
4.创建FurnController.java , 处理添加请求
@Controller public class FurnController { //注入配置FurnService @Resource private FurnService furnService; /** * 解读 * 1、响应客户端的添加请求 * 2、@RequestBody: 使用 SpringMVC 的 @RequestBody 将客户端提交的 json 数据,封装成 JavaBean 对象 * 3、@ResponseBody: 服务器返回的数据格式是按照 json 来返回的(底层是按照http协议进行协商) */ @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 return Msg.success(); } else { //校验失败,把校验错误信息封装到Msg对象,并返回 return Msg.fail().add("errorMsg", map); } }
- 使用Postman 来完成Controller 层的测试, 通过Postman 添加Furn 数据
使用Postman 测试时,因为我们前台是发送的json 数据,被服务器接收到后,转成javabean 数据,因此pom.xml 需要引入jackson,处理json 数据, 否则后台会报错.
//报错 Content type 'application/json;charset=UTF-8' not supported
<!-- 引入jackson,处理json数据 --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.12.4</version> </dependency>
点击添加按钮, 可以出现添加家居的对话框, 修改C:\Users\Administrator\Desktop\desktop\d\SSM-Vue 整合项目-temp\ssm_vue\src\views\HomeView.vue , 说明el-dialog 从Dialog 对话框获取, 表单代码从Form 表单获取,组合一下并调整一下即可
<!-- 添加家居的弹窗 说明: 1. el-dialog :v-model="dialogVisible" 表示对话框, 和dialogVisible 变量双向绑定,控制是否显示对话框 2. el-form :model="form" 表示表单 ,数据和 form数据变量双向绑定 3. el-input v-model="form.name" 表示表单的input控件,名字为name 需要和后台Javabean[Furn] 属性一致 4. 在前端中, 对象的属性是可以动态生成的 , 这个知识点,我们在讲前端技术栈讲过 --> <el-dialog title="提示" v-model="dialogVisible" width="30%"> <el-form :model="form" :rules="rules" ref="form" label-width="120px"> <el-form-item label="家居名" prop="name"> <el-input v-model="form.name" style="width: 50%"></el-input> {{serverValidErrors.name}} </el-form-item> <el-form-item label="厂商" prop="maker"> <el-input v-model="form.maker" style="width: 50%"></el-input> {{serverValidErrors.maker}} </el-form-item> <el-form-item label="价格" prop="price"> <el-input v-model="form.price" style="width: 50%"></el-input> {{serverValidErrors.price}} </el-form-item> <el-form-item label="销量" prop="sales"> <el-input v-model="form.sales" style="width: 50%"></el-input> {{serverValidErrors.sales}} </el-form-item> <el-form-item label="库存" prop="stock"> <el-input v-model="form.stock" style="width: 50%"></el-input> {{serverValidErrors.stock}} </el-form-item> </el-form> <template #footer> <span class="dialog-footer"> <el-button @click="dialogVisible = false">取 消</el-button> <el-button type="primary" @click="save">确 定</el-button> </span> </template> </el-dialog> //增加数据, 一定要, 否则你会发现,在后面弹出的表单不能输入数据 data() { return { form: {}, //增加方法 methods: { add() { this.dialogVisible = true this.form = {} } } } } //增加点击新增的按钮事件 <div style="margin: 10px 0"> <el-button type="primary" @click="add">新增</el-button> <el-button>其它</el-button> </div>
- 完成测试: 看看点击新增按钮,能否正常的弹窗添加家居的对话框(含有表单)
- 项目前端安装axios, 用于发送Ajax 请求给后台, 一定要注意
- 创建工具文件ssm_vue\src\utils\request.js , 用于创建axios request 对象
//引入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) }) //response拦截器 //可以在调用接口响应后,统一的处理返回结果 request.interceptors.response.use( response => { let res = response.data //如果返回的是文件,就返回 if (response.config.responseType === 'blob') { return res } //如果是string, 就转成json对象 if (typeof res === 'string') { //如果res 不为null, 就进行转换成json对象 res = res ? JSON.parse(res) : res } return res; }, error => { console.log("err", error) return Promise.reject(error); } ) //导出request对象, 在其它文件就可以使用 export default request
- 修改HomeView.vue , 在methods 编写save 方法, 并测试会出现跨域问题
//1. 将form 表单提交给/api/save 的接口 //2. /api/save 等价http∶//locaLhost∶10001/save //3. 如果成功,就进入then 方法 //4.res 就是返回的信息 //5.查看mysql 看看数据是否保存 save() { // =======说明====... request.post("/api/save", this.form).then(res => { console.log(res) this.dialogVisible = false }) }
11.这里容易出现的问题
- 一定要确定request.post(“/api/save”) 被代理后的url , 是项目后台服务对应提供的API接口url, 否则报404。
- 当跨域执行时请求,浏览器还是提示http://localhost:5927/api/xxx , 所以不要认为是api没有替换你的配置.
注意事项和细节
- Postman 测试时, 要指定content-type ,否则会报错415
- 如果需要将提交的json 数据, 封装到对应的Javabean, 需要配置@RequestBody , 否则会报错500
- 如果需要返回json 数据, 需要在方法上, 配置@ResponseBody , 否则会报错404
实现功能05-显示家居信息
需求分析/图解
思路分析
- 完成后台代码从dao -> serivce -> controller , 并对每层代码进行测试
- 完成前台代码, 使用axios 发送http 请求,返回所有家居数据, 将数据绑定显示
代码实现
- 修改FurnService.java 和FurnServiceImpl.java, 增加findAll 方法
//FurnService public List<Furn> findAll();
//FurnServiceImpl //返回所有家居数据,传入null 即可 @Override public List<Furn> findAll() { return furnMapper.selectByExample(null); }
- 修改FurnServiceTest.java ,测试findAll.
@Test public void findAll() { List<Furn> furnList = furnService.findAll(); for (Furn furn : furnList) { System.out.println(furn); } }
- 修改FurnController.java , 处理显示请求, 并使用Postman 完成测试
@ResponseBody @RequestMapping("/furns") public Msg listFurns() { List<Furn> furnList = furnService.findAll(); return Msg.success().add("furnsList", furnList); }
- 修改HomeView.vue , 编写list 方法
//修改一下el-table <el-table : data="tableData" stripe style="width: 100%"> <el-table-column prop="id" label="ID" sortable > </el-table-column> <el-table-column prop="name" label="家居名" > </el-table-column> <el-table-column prop="maker" label="厂家"> </el-table-column> <el-table-column prop="price" label="价格"> </el-table-column> <el-table-column prop="sales" label="销量"> </el-table-column> <el-table-column prop="stock" label="库存"> </el-table-column> <el-table-column fixed="right" label="操作" width="100"> <template #default="scope"> <el-button @click="handleEdit(scope.row)" type="text">编辑</el-button> <el-button type="text">删除</el-button> </template> </el-table-column> </el - table > //修改一下tableData: [] data() { return { form: {}, dialogVisible: false, search: '', tableData: [] } } //在created() 调用list() 完成页面数据获取 created() { this.list() } //编写list() method list() { //请求显示家居列表-带检索 request.get("/api/furns").then(res => { //绑定tableData, 显示在表格 this.tableData = res.data.extend.furnsList }) } //在save() 调用后,调用list() 刷新页面 save() { // =======说明====... request.post("/api/save", this.form).then(res => { console.log(res) this.dialogVisible = false this.list() }) }
- 完成测试,看看是否可以显示家居列表信息.
- 修改src\utils\request.js 增加response 拦截器, 统一处理响应后结果
//引入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) }) //response拦截器 //可以在调用接口响应后,统一的处理返回结果 request.interceptors.response.use( response => { let res = response.data //如果返回的是文件,就返回 if (response.config.responseType === 'blob') { return res } //如果是string, 就转成json对象 if (typeof res === 'string') { //如果res 不为null, 就进行转换成json对象 res = res ? JSON.parse(res) : res } return res; }, error => { console.log("err", error) return Promise.reject(error); } ) //导出request对象, 在其它文件就可以使用 export default request
修改Home.vue , 简化返回处理
- 完成测试.