浏览器页面点击添加按钮,弹出提示框,填写家居信息,点击确定,可以把数据添加到数据库中。
后端项目使用的是 ssm 框架,src 下分为 bean,dao,service,controller,utils层,其中 controller 层由springmvc 接管,service 层由 spring 接管,dao 层由 mybatis 接管。
相比于传统的 Javaweb 项目,它的三层结构并没有发生根本变化,仅仅是框架化了,各组件由框架接管。原本的 jsp 则页面变成了 vue 前端项目。
由于使用了逆向工程,bean 层、dao 层以及dao层接口对应的mapper映射文件已经生成,因此暂时不必在这两层编写代码了。
(1)Service层,创建对应的接口和实现类
FurnService.java(接口)
package com.li.furn.service;
import com.li.furn.bean.Furn;
/**
* @author 李
* @version 1.0
*/
public interface FurnService {
//添加
public void save(Furn furn);
}
FurnServiceImpl.java(实现类)
package com.li.furn.service.impl;
import com.li.furn.bean.Furn;
import com.li.furn.dao.FurnMapper;
import com.li.furn.service.FurnService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* @author 李
* @version 1.0
*/
@Service //注入spring容器
public class FurnServiceImpl implements FurnService {
//自动装配 FurnMapper接口对象(代理对象)
@Resource
private FurnMapper furnMapper;
//已经在spring配置文件中开启事务
@Override
public void save(Furn furn) {
furnMapper.insertSelective(furn);
}
}
测试代码:
package com.li.furn.test.service;
import com.li.furn.bean.Furn;
import com.li.furn.service.FurnService;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.math.BigDecimal;
/**
* @author 李
* @version 1.0
*/
public class FurnServiceTest {
//spring容器
private ApplicationContext ioc;
//从spring容器中获取的是FurnService接口的代理对象
private FurnService furnService;
@Before
public void init() {
ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
//通过FurnService.class类型获取FurnService接口对象的代理对象
furnService = ioc.getBean(FurnService.class);
}
@Test
public void FurnServiceTest() {
//添加数据
Furn furn = new Furn(null, "复古沙发", "森林之家",
new BigDecimal(1088), 12, 28,
"/assets/images/product-image/7.jpg");
furnService.save(furn);
System.out.println("添加成功");
//关闭sqlSession的动作底层会自动释放
}
}
测试成功:
(2)关于家居图片路径
给新增的家居增加一个默认图片的路径值,修改Furn.java(部分代码):
//默认图片路径
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 && !imgPath.equals("")
// =>使用StringUtils.hasText()代替,该方法要求传入的字符串不是null,并且不是"",并且不能全为空格
if (StringUtils.hasText(imgPath)) {
this.imgPath = imgPath;
}
}
(3)bean层创建Msg.java,用来返回给前端 Json 数据的通用类,本质就是一个”协议“
package com.li.furn.bean;
import java.util.HashMap;
import java.util.Map;
/**
* @author 李
* @version 1.0
* 用来返回给前端Json数据的通用类
*/
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;//返回的是当前Msg对象
}
//省略setter,getter方法
}
(4)创建FurnController.java,处理添加家居请求
package com.li.furn.controller;
import com.li.furn.bean.Furn;
import com.li.furn.bean.Msg;
import com.li.furn.service.FurnService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
/**
* @author 李
* @version 1.0
*/
@Controller//由springmvc来处理
public class FurnController {
@Resource
private FurnService furnService;
/**
* 1.响应客户端添加家居的请求
* 2.@RequestBody 注解将客户端提交的json数据封装成 Javabean 对象。
* 3.@ResponseBody 服务器返回的数据是按照json来返回的(底层是按照 http协议进行协商)
*
* @param furn
* @return
*/
@ResponseBody
@PostMapping("/save")
public Msg save(@RequestBody Furn furn) {
furnService.save(furn);
//如果没有出现异常,就返回成功
Msg success = Msg.success();
return success;
}
}
(5)Postman对Controller层进行测试
使用postman测试时,因为我们前台发送的是json数据,被服务器接收到后,转成Javabean数据,因此pom.xml需要引入jackson,处理json数据,否则后台会报错。
<!--引入jackson--> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.12.4</version> </dependency>
请求结果:


(1)修改HomeView.vue页面,代码略。
<template>
<div>
<!--增加按钮和搜索框-->
<div style="margin:10px 5px">
<el-button type="primary" @click="add">新增</el-button>
<el-button>其他</el-button>
</div>
<div style="margin:10px 5px">
<el-input v-model="search" style="width: 30%" placeholder="请输入关键字"/>
<el-button style="margin-left: 10px" type="primary">查找</el-button>
</div>
<!--表格-->
...
<!--添加家居的弹窗
1.el-dialog v-model="dialogVisible" 表示对话框,
和 dialogVisible 变量双向绑定,控制是否显示对话框
2.el-form:mode="form" 表示表单数据和form数据变量双向绑定
3.el-input v-mode="form.name" 表示表单的input控件,
名字为name,必须需要和后端Javabean属性一致
4.在前端中,对象的属性是可以动态生成的-->
<el-dialog title="提示" v-model="dialogVisible" width="40%">
<el-form :model="form" label-width="120px">
<el-form-item label="家居名">
<el-input v-model="form.name" style="width: 80%"></el-input>
...
...
</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>
</div>
</template>
<script>
import request from '@/utils/request.js'
//导出组件
export default {
name: 'HomeView',
components: {},
data() {
return {
search: '',
dialogVisible: false,
form: {},//定义一个空表单
tableData: [...]
}
},
methods: {
add() {//显示添加对话框
//显示对话框
this.dialogVisible = true;
//每次点击都要清空上一次的表单数据
this.form = {};
},
save() {//将填写的表单数据发送给后端
//第一个参数为url,第二个参数是请求携带的数据
request.post("/api/save", this.form).then(res => {
console.log("res-", res)
this.dialogVisible = false;//隐藏表单
})
}
}
}
</script>
效果如下:
(2)安装axios,用于发送ajax请求给后台
(3)在前端项目的src目录下创建utlis目录,utils目录下创建工具文件request.js,用于创建axios request对象,发送ajax请求。
//引入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;
如果启动前端项目,提示找不到axios,需要把光标放在import axios from ‘axios’ 的提示上,会有一个修复提示,点击导入axios即可。
(4)修改HomeView.vue,在methods编写save方法,并测试。
...
save() {//将填写的表单数据发送给后端
//第一个参数为url,第二个参数是请求携带的数据
request.post('http://localhost:8080/save', this.form).then(res => {
console.log("res-", res)
this.dialogVisible = false;//隐藏表单
})
}
...
测试向后端项目发送请求,因为前后端的服务ip不一致,会出现跨域问题,浏览器会阻止访问:
(5)在项目目录下的vue.config.js,解决跨域问题
...
module.exports = {
devServer: {
port: 10001,//启动端口
proxy: {//设置代理,必须填
'/api': {//设置拦截器 拦截器格式
target: 'http://localhost:8080/',//代理的目标地址,就是/api代替的地址
changeOrigin: true,//是否设置同源,如果为true,就允许跨域
pathRewrite: {//路径重写
'/api': ''//选择忽略拦截器里面的单词
}
}
}
}
}
因为修改了配置文件,npm serve 需要重启,否则不能识别。
再次测试,成功发送数据:
在页面中展示数据库的家居信息。
分层完成,由于使用了逆向工程,bean 层、dao 层以及dao层接口对应的mapper映射文件已经生成,因此暂时不必在这两层编写代码了。
(1)service层,修改FurnService.java和FurnServiceImpl.java,增加findAll()方法。(展示不考虑分页问题)
FurnService.java:
//查询所有的家居信息
public List<Furn> findAll();
FurnServiceImpl.java:
@Override
public List<Furn> findAll() {
//如果传入为null表示返回所有的家居信息
return furnMapper.selectByExample(null);
}
(2)controller层,FurnController.java 处理现实家居的请求
@RequestMapping("/furns")
@ResponseBody
public Msg listFurns() {
List<Furn> furnList = furnService.findAll();
//将数据封装到 Meg对象中返回
Msg msg = Msg.success();
msg.add("furnList", furnList);
return msg;
}
(3)postman测试成功
(1)修改src/utils/request.js,增加response拦截器,统一处理响应后的结果
//response拦截器,可以在调用接口响应后,统一的处理返回结果
request.interceptors.response.use(
response => {
let res = response.data;
//如果返回的是文件
if (response.config.responseType === 'blob') {
return res;
}
//如果返回的是string,就转成json对象
if (typeof res === 'string') {
//如果不为空,就转成json对象
res = res ? JSON.parse(res) : res;
}
return res;
}, error => {
//如果失败
console.log("err=", error);
return Promise.reject(error);
})
(2)修改HomeView.vue,当现实页面之前就发出请求,然后将接收的数据显示到页面上
<template>
<div>
...
<!--表格显示家居新-->
<el-table :data="tableData" stripe style="width: 90%">
<el-table-column prop="id" label="ID" sortable></el-table-column>
<el-table-column prop="name" label="家居名"></el-table-column>
...
...
<el-table-column fixed="right" label="操作" width="100">
<template #default="scope">
<el-button link type="primary" size="small"
@click="handleEdit(scope.row)">编辑
</el-button>
<el-button link type="primary" size="small">删除</el-button>
</template>
</el-table-column>
</el-table>
...
</div>
</template>
<script>
import request from '@/utils/request.js'
//导出组件
export default {
name: 'HomeView',
components: {},
data() {
return {
search: '',
dialogVisible: false,
form: {},//定义一个空表单
tableData: []
}
},
created() {//生命周期函数
this.list();
},
methods: {
add() {//显示添加对话框
...
},
save() {//将填写的表单数据发送给后端
request.post("/api/save", this.form).then(res => {
console.log("res-", res)
this.dialogVisible = false;
//调用list方法,刷新页面显示的数据
this.list();
})
},
list() {//list方法,请求返回家居信息,当我们打开页面的时候,该方法就应该自动触发
request.get("/api/furns").then(res => {//res已经经过拦截器的处理>res=res.data
//根据res的结构来获取数据
this.tableData = res.extend.furnList;
})
}
}
}
</script>
我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden
只是想确保我理解了事情。据我目前收集到的信息,Cucumber只是一个“包装器”,或者是一种通过将事物分类为功能和步骤来组织测试的好方法,其中实际的单元测试处于步骤阶段。它允许您根据事物的工作方式组织您的测试。对吗? 最佳答案 有点。它是一种组织测试的方式,但不仅如此。它的行为就像最初的Rails集成测试一样,但更易于使用。这里最大的好处是您的session在整个Scenario中保持透明。关于Cucumber的另一件事是您(应该)从使用您的代码的浏览器或客户端的角度进行测试。如果您愿意,您可以使用步骤来构建对象和设置状态,但通常您
华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o
C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.
//1.验证返回状态码是否是200pm.test("Statuscodeis200",function(){pm.response.to.have.status(200);});//2.验证返回body内是否含有某个值pm.test("Bodymatchesstring",function(){pm.expect(pm.response.text()).to.include("string_you_want_to_search");});//3.验证某个返回值是否是100pm.test("Yourtestname",function(){varjsonData=pm.response.json
MIMO技术的优缺点优点通过下面三个增益来总体概括:阵列增益。阵列增益是指由于接收机通过对接收信号的相干合并而活得的平均SNR的提高。在发射机不知道信道信息的情况下,MIMO系统可以获得的阵列增益与接收天线数成正比复用增益。在采用空间复用方案的MIMO系统中,可以获得复用增益,即信道容量成倍增加。信道容量的增加与min(Nt,Nr)成正比分集增益。在采用空间分集方案的MIMO系统中,可以获得分集增益,即可靠性性能的改善。分集增益用独立衰落支路数来描述,即分集指数。在使用了空时编码的MIMO系统中,由于接收天线或发射天线之间的间距较远,可认为它们各自的大尺度衰落是相互独立的,因此分布式MIMO
遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg
1.在Python3中,下列关于数学运算结果正确的是:(B)a=10b=3print(a//b)print(a%b)print(a/b)A.3,3,3.3333...B.3,1,3.3333...C.3.3333...,3.3333...,3D.3.3333...,1,3.3333...解析: 在Python中,//表示地板除(向下取整),%表示取余,/表示除(Python2向下取整返回3)2.如下程序Python2会打印多少个数:(D)k=1000whilek>1: print(k)k=k/2A.1000 B.10C.11D.9解析: 按照题意每次循环K/2,直到K值小于等
通常,数组被实现为内存块,集合被实现为HashMap,有序集合被实现为跳跃列表。在Ruby中也是如此吗?我正在尝试从性能和内存占用方面评估Ruby中不同容器的使用情况 最佳答案 数组是Ruby核心库的一部分。每个Ruby实现都有自己的数组实现。Ruby语言规范只规定了Ruby数组的行为,并没有规定任何特定的实现策略。它甚至没有指定任何会强制或至少建议特定实现策略的性能约束。然而,大多数Rubyist对数组的性能特征有一些期望,这会迫使不符合它们的实现变得默默无闻,因为实际上没有人会使用它:插入、前置或追加以及删除元素的最坏情况步骤复
在ruby中,你可以这样做:classThingpublicdeff1puts"f1"endprivatedeff2puts"f2"endpublicdeff3puts"f3"endprivatedeff4puts"f4"endend现在f1和f3是公共(public)的,f2和f4是私有(private)的。内部发生了什么,允许您调用一个类方法,然后更改方法定义?我怎样才能实现相同的功能(表面上是创建我自己的java之类的注释)例如...classThingfundeff1puts"hey"endnotfundeff2puts"hey"endendfun和notfun将更改以下函数定