一、单元测试Unit Test
一般用来测试业务层
关于使用:引入依赖"
<!-- 单元测试-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
业务测试的类名必须以Tests
结尾且类名上面加上注解:@SpringBootTest
package com.stedu;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.stedu.model.Member;
import com.stedu.model.search.MemberSearchBean;
import com.stedu.service.MemberService;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
class Crm2026ApplicationTests {
@Autowired//依赖注入:字段注入
private MemberService memberService;
//单元测试 :
@DisplayName("单元测试hello")//单元测试名字,方便用户体验的
@Test
public void testHello(){
Integer a = 10;
//测试断言:断言通过则单元测试通过 ,断言不通过则单元测试不通过
//使用工具类:Assertions
Assertions.assertEquals(20,a);//不通过,期待的是20,但是实际是10;
}
@DisplayName("测试获取所有会员")
@Test
public void testAll(){//单元测试不能有参数
Page<Member> page = new Page<>(1,5);
MemberSearchBean msb = new MemberSearchBean();
msb.setName("晓");
page = this.memberService.findAll(page,msb);
Long total = page.getTotal();//总数
Assertions.assertEquals(4,total);
List<Member> members = page.getRecords();//获取所有查询记录
}
}
二 、Vue—Element Plus
1.安装Element Plus :
pnpm install element-plus
2.安装图标库 :
安装Element Plus图标库:
https://element-plus.org/zh-CN/component/icon.html
pnpm install @element-plus/icons-vue
安装后验证 :
3.安装之后进行配置
导入相关库:
import ElementPlus from 'element-plus'//引入element-plus主程序库
import 'element-plus/dist/index.css'//引入css文件
import zhCn from 'element-plus/es/locale/lang/zh-cn'//导入中文本地化
import * as ElementPlusIconsVue from '@element-plus/icons-vue'//引入所有的图标库
//设置使用Element-plus:注意位置
app.use(ElementPlus, {
locale: zhCn,
})
4.正式使用Element-plus写前端示例:
需要写的内容写在<template></template>
标签中
书写顺序 :
(1)先写表单/表格等页面展示部分
(2)然后根据事件需要先创建对象
(3)绑定事件:比如性别:当选中女的时候是 真正的选中,
(1)其实是只有页面的展示的部分 ,还不能具体的真正选中数据或者实现真正操作 需要 :data 属性
表格
比如我们在页面展示表格:
(1)html部分展示表格 :框架
(2)加上属性真正展示:实现真正的展示要加上 属性:data
必须加上:
冒号开头的属性值是变量。这个变量必须在js里面有
<!-- 表格区 -->
<div class="grid">
<el-table :data="members" stripe border class="data-grid">
<el-table-column prop="id" label="ID" width="80"/>
<el-table-column prop="phone" label="手机号" width="150"/>
<el-table-column prop="name" label="姓名" width="150"/>
<el-table-column prop="pinyin" label="拼音" width="180"/>
<el-table-column prop="sex" label="性别" width="60"/>
<el-table-column prop="birthday" label="出生日期" width="150"/>
<el-table-column prop="email" label="邮箱" width="240"/>
<el-table-column prop="wechat" label="微信号" width="240"/>
<el-table-column prop="description" label="备注" show-overflow-tooltip/>
</el-table>
</div>
(3)创建响应式对象: JS里面,改变对象的值,页面会重新渲染。数据的变化驱动页面重新刷新
<script setup>
import {onMounted, ref, reactive} from "vue"
import api from "@/util/api";
import {CirclePlus, Delete, Edit, Refresh, Search} from "@element-plus/icons-vue";
///////////////////////////////////
let members = ref();//创建一个响应式对象
//查询全部会员
async function search(pageNo = 1, pageSize = 10) {
let resp = await api({
url: "/members",
method: "get",
params: {
pageNo,
pageSize
}
});
//console.log(resp);
members.value = resp.data.records;//会员数据
}
//当组件挂载完毕之后触发
onMounted(() => {
search();
});
</script>
按钮:
思路:先从官网加上 首先最基础的展示,然后添加修饰(按钮的修饰官网 提供的很全面)最后 绑定事件 :添加函数:自己写函数
<!-- 按钮区-->
<div class="action">
<!-- 通过查看官网 ,设置type的属性primary就是让按钮背景颜色变成蓝色,:icon就是根据官网给他设置图标,
然后@click=""是点击事件绑定,触发对应的方法
关于@click=""中的():需要事件对象时省略括号,需要传参时加括号。-->
<el-button type="primary" :icon="CirclePlus" @click="add">新增</el-button>
<el-button type="primary" :icon="Edit">修改</el-button>
<el-button type="primary" :icon="Search" @click="search()">查询</el-button>
<el-button type="primary" :icon="Refresh" @click="reset">重置</el-button>
<el-button type="danger" :icon="Delete" @click="remove">删除</el-button>
</div>
但是还无法点击,绑定事件,添加对应的函数:也就是@click=""
是点击事件绑定,触发对应的方法部分即可 。
分页条 :
模板 :
<el-pagination
v-model:current-page="绑定数据模型里面的页码 "
v-model:page-size="绑定数据模型里面的页面大小"
:page-sizes="[100, 200, 300, 400]"
layout="total, sizes, prev, pager, next, jumper"
:total="绑定数据模型里面的总页数"
/>
示例:
<!-- 分页条 -->
<div class="pagination">
<el-pagination
v-model:current-page="memberPi.pageNo"
v-model:page-size="memberPi.pageSize"
:page-sizes="[10, 20, 30, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
:total="memberPi.total"
class="member-pi"
background
@change="memberPiChange"
/>
</div>
上面对应的数据模型:
//会员数据分页
let memberPi = reactive({
pageNo: 1,
pageSize: 10,
total: 0
});
具体赋值及其他操作
全部js代码部分
<script setup>
import {onMounted, ref, reactive} from "vue"
import api from "@/util/api";
import {CirclePlus, Delete, Edit, Refresh, Search} from "@element-plus/icons-vue";
///////////////////////////////////
let members = ref();//创建一个响应式对象
//查询全部会员
async function search(pageNo = 1, pageSize = 10) {
let resp = await api({
url: "/members",
method: "get",
params: {
pageNo,
pageSize
}
});
//console.log(resp);
members.value = resp.data.records;//会员数据
memberPi.pageNo = resp.data.current;
memberPi.pageSize = resp.data.size;
memberPi.total = resp.data.total;
}
//当页码或页面大小改变时触发
function memberPiChange(pageNo, pageSize) {
//console.log(pageNo, pageSize);
search(pageNo, pageSize);
}
//当组件挂载完毕之后触发
onMounted(() => {
search();
});
</script>
查询区域
<!-- 查询区 -->
<div class="search">
<el-form inline :model="memberSearchModel" ref="memberSearchForm">
<el-form-item label="ID:" prop="id">
<el-input v-model="memberSearchModel.id" placeholder="请输入会员ID"/>
</el-form-item>
<el-form-item label="姓名:" prop="name">
<el-input v-model="memberSearchModel.name" placeholder="请输入会员姓名"/>
</el-form-item>
<el-form-item label="性别:" prop="sex">
<el-select v-model="memberSearchModel.sex" :empty-values="[null]" style="width: 200px">
<el-option label="不限" value=""/>
<el-option label="男" value="男"/>
<el-option label="女" value="女"/>
</el-select>
</el-form-item>
<el-form-item label="出生日期:" prop="birthdayRange">
<el-date-picker
type="daterange"
range-separator="~"
start-placeholder="日期从"
end-placeholder="日期止"
v-model="memberSearchModel.birthdayRange"
value-format="YYYY-MM-DD"
/>
</el-form-item>
<el-form-item label="手机号:" prop="phone">
<el-input v-model="memberSearchModel.phone" placeholder="请输入会员手机号"/>
</el-form-item>
</el-form>
</div>
5.删除操作的实现(后端)
servcie层方法
package com.study.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.study.model.Member;
import com.study.model.search.MemberSearchBean;
import java.util.List;
public interface MemberService {
//查询全部客户
Page<Member> findAll(Page<Member> page, MemberSearchBean msb);
//删除操作:批量删除(多个--传集合:是客户Id也就是整型),返回受影响的行数
int delete(List<Integer> ids);
}
package com.study.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.study.model.Member;
import com.study.model.search.MemberSearchBean;
import java.util.List;
public interface MemberService {
//查询全部客户
Page<Member> findAll(Page<Member> page, MemberSearchBean msb);
//删除操作:批量删除(多个--传集合:是客户Id也就是整型),返回受影响的行数
int delete(List<Integer> ids);
}
根据Id删除mybatis-plus底层已经提供了,直接调方法就行,所以不用写mapper层了
Controller层:
package com.study.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.study.model.Member;
import com.study.model.search.MemberSearchBean;
import com.study.service.MemberService;
import com.study.util.JsonResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("api/v1/members" )//接收前端的请求,路径与前端发送请求的路径一致
public class MemberController {
private MemberService memberService;
@Autowired//依赖注入:创建对象:
public void setMemberService(MemberService memberService) {
this.memberService = memberService;
}
//查询全部客户:
@GetMapping
public ResponseEntity<JsonResult<?>> findAll(
@RequestParam(defaultValue = "1") Integer pageNo,
@RequestParam(defaultValue = "15") Integer pageSize,
MemberSearchBean msb){
Page<Member> page = new Page<>(pageNo,pageSize);
Page<Member> all = memberService.findAll(page, msb);
return ResponseEntity.ok(JsonResult.success(all));
}
@DeleteMapping//删除操作
public ResponseEntity<JsonResult<?>> delete(@RequestBody Integer[] ids){
int count = memberService.delete(List.of(ids));
if(count==0){
return ResponseEntity.ok(JsonResult.fail("删除会员失败"));
}
else {
return ResponseEntity.ok(JsonResult.success(count));
}
}
}
Service层:
package com.study.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.study.model.Member;
import com.study.model.search.MemberSearchBean;
import java.util.List;
public interface MemberService {
//查询全部客户
Page<Member> findAll(Page<Member> page, MemberSearchBean msb);
//删除操作:批量删除(多个--传集合:是客户Id也就是整型),返回受影响的行数
int delete(List<Integer> ids);
}
package com.study.service.impl;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.study.mapper.MemberMapper;
import com.study.model.Member;
import com.study.model.search.MemberSearchBean;
import com.study.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service//控制反转:创建对象
public class MemberServiceImpl implements MemberService {
@Autowired
private MemberMapper memberMapper;
@Override
public Page<Member> findAll(Page<Member> page, MemberSearchBean msb) {
return memberMapper.findAll(page,msb);
}
@Override
public int delete(List<Integer> ids) {
return memberMapper.deleteByIds(ids);//注意选对方法
}
}
其他具体操作可以参考真正的项目实战博客。