# 第2章 预约管理-检查项-检查组管理
内容介绍
学习目标
- 掌握检查项分页查询实现过程
- 掌握删除检查项实现过程
- 掌握编辑检查项实现过程
- 掌握新增检查组实现过程
- 掌握检查组分页查询实现过程
- 掌握编辑检查组实现过程
- 了解常见的图片存储方案
1. 检查项分页
【分析】
-
需求分析:点击左侧菜单进入检查项页面,分页查询。 用户输入条件,分页查询。
-
数据库表:t_checkitem 查询
-
编码分析
3.1. 前端编码分析
3.1.1. 点击左侧菜单,或用户输入条件进行分页查询,都发起分页查询请求 /checkitem/findPage.do post 参数QueryPageBean对象 得到PageResult
3.1.2. 点击具体的页码,也会发起分页请求
3.2. 后端编码分析
3.2.1. controller接收请求 @RequestBody QueryPageBean queryPageBean
3.2.2. controller调用service业务处理
分页插件使用步骤
a.加入分页插件依赖
b.配置分页插件
c.设置当前页码 每页条数
d.需要被分页的查询语句编码(调用dao)
e.返回分页对象
3.2.3.dao持久层接口 映射
【目标】
1:熟悉分页功能中的请求参数
2:熟悉分页功能中的响应数据
3:检查项分页功能实现
【路径】
1:前台代码
(1)定义分页相关模型数据
(2)定义分页方法
- 使用钩子函数,初始化数据
(3)完善分页方法执行时机
2:后台代码
(1)CheckItemController.java
(2)CheckItemService.java(服务接口)
(3)CheckItemServiceImpl.java(服务实现类)
(4)CheckItemDao.java(Dao接口)
(5)CheckItemDao.xml(Mapper映射文件)
【讲解】
回顾:正常分页逻辑(不使用PageHelper):
-
写2条sql
第一条sql:select count() from t_checkitem where name = '传智身高' -->封装到PageResult中total
第二条sql:select * from t_checkitem where name = '传智身高' limit ?,? -->封装到PageResult中rows*
-
limit ?,? :
第一个问号:表示从第几条开始检索 计算:(currentPage-1)*pageSize
第二个问号:表示当前页最多显示的记录数, 计算:pageSize
本项目所有分页功能都是基于ajax的异步请求来完成的,请求参数和后台响应数据格式都使用json数据格式。
1:请求参数包括页码、每页显示记录数、查询条件。
请求参数的json格式为:{currentPage:1,pageSize:10,queryString:''itcast''}
2:后台响应数据包括总记录数、当前页需要展示的数据集合。
响应数据的json格式为:{total:1000,rows:[]}
1.1. 前台代码
1.1.1. 定义分页相关模型数据
pagination: {//分页相关模型数据
currentPage: 1,//当前页码
pageSize:10,//每页显示的记录数
total:0,//总记录数
queryString:null//查询条件
},
dataList: [],//当前页要展示的分页列表数据
1.1.2. 定义分页方法
在页面中提供了findPage方法用于分页查询,为了能够在checkitem.html页面加载后直接可以展示分页数据,可以在VUE提供的钩子函数created中调用findPage方法
created() {
//3.1.1. 点击左侧菜单,或用户输入条件进行分页查询,都发起分页查询请求 /checkitem/findPage.do post 参数QueryPageBean对象 得到PageResult
this.findPage();
},
//分页查询
findPage() {
//定义变量
var queryPageBean = {
currentPage:this.pagination.currentPage,
pageSize:this.pagination.pageSize,
queryString:this.pagination.queryString
}
//3.1.1. 点击左侧菜单,或用户输入条件进行分页查询,都发起分页查询请求 /checkitem/findPage.do post 参数QueryPageBean对象 得到PageResult
axios.post("/checkitem/findPage.do",queryPageBean).then(res=>{
//展示结果 PageResult == res.data
this.pagination.total = res.data.total;//总记录数
this.dataList = res.data.rows;//当前页面显示的数据
})
},
1.1.3. 完善分页方法执行时机
除了在created钩子函数中调用findPage方法查询分页数据之外,当用户点击查询按钮或者点击分页条中的页码时也需要调用findPage方法重新发起查询请求。
为查询按钮绑定单击事件,调用findPage方法
<el-button @click="handleCurrentChange(1)" class="dalfBut">查询</el-button>
为分页条组件绑定current-change事件,此事件是分页条组件自己定义的事件,当页码改变时触发,对应的处理函数为handleCurrentChange
<div class="pagination-container">
<el-pagination
class="pagiantion"
@current-change="handleCurrentChange"
:current-page="pagination.currentPage"
:page-size="pagination.pageSize"
layout="total, prev, pager, next, jumper"
:total="pagination.total">
</el-pagination>
</div>
定义handleCurrentChange方法
//切换页码
handleCurrentChange(currentPage) {
// 3.1.2. 点击具体的页码,也会发起分页请求
this.pagination.currentPage = currentPage;
this.findPage();
},
1.2. 后台代码
1.2.1. Controller
在CheckItemController中增加分页查询方法
/**
* 检查项分页
*/
@RequestMapping(value = "/findPage",method = RequestMethod.POST)
public PageResult findPage(@RequestBody QueryPageBean queryPageBean){
try {
return checkItemService.findPage(queryPageBean);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
1.2.2. Service服务实现类
在CheckItemService服务接口中扩展分页查询方法
/**
* 检查项分页
*/
PageResult findPage(QueryPageBean queryPageBean);
在CheckItemServiceImpl服务实现类中实现分页查询方法,基于Mybatis分页助手插件实现分页
/**
* 检查项分页
* queryPageBean.getCurrentPage():当前页码
* queryPageBean.getPageSize():每页显示条数
* queryPageBean.getQueryString():用户输入的查询条件
*/
@Override
public PageResult findPage(QueryPageBean queryPageBean) {
//c.设置当前页码 每页条数
PageHelper.startPage(queryPageBean.getCurrentPage(),queryPageBean.getPageSize());
//d.需要被分页的查询语句编码(调用dao)
Page<CheckItem> page = checkItemDao.selectByCondition(queryPageBean.getQueryString());
//e.返回分页对象
return new PageResult(page.getTotal(),page.getResult());
}
或者:
@Override
public PageResult pageQuery(Integer currentPage, Integer pageSize, String queryString) {
/**采用mybatis的分页插件*/
// 1:完成对分页初始化工作
PageHelper.startPage(currentPage,pageSize);
// 2:查询
List<CheckItem> list = checkItemDao.selectByCondition(queryString);
// 3:后处理,PageHelper会根据查询的结果再封装成PageHealper对应的实体类
PageInfo<CheckItem> pageInfo = new PageInfo<>(list);
// 组织PageResult
return new PageResult(pageInfo.getTotal(),pageInfo.getList());
}
1.2.3. Dao接口
在CheckItemDao接口中扩展分页查询方法
/**
* 检查项分页
* @param queryString
* @return
*/
Page<CheckItem> selectByCondition(String queryString);
1.2.4. Mapper映射文件
在CheckItemDao.xml文件中增加SQL定义
<!--检查项分页-->
<select id="selectByCondition" parameterType="string" resultType="com.itheima.pojo.CheckItem">
select * from t_checkitem
<if test="value != null and value.length > 0 ">
where code = #{value} or name = #{value}
</if>
</select>
如果使用if进行判断,这里需要是value读取值,不能改成其他参数。
【小结】
1:前台代码
(1)定义分页相关模型数据
(2)定义分页方法
- 使用钩子函数,初始化数据
(3)完善分页方法执行时机
- 查询按钮
2:后台代码
(1)CheckItemController.java
(2)CheckItemService.java(服务接口)
(3)CheckItemServiceImpl.java(服务实现类)
在CheckItemServiceImpl服务实现类中实现分页查询方法,基于Mybatis分页助手插件实现分页
public PageResult pageQuery(Integer currentPage, Integer pageSize, String queryString) {
PageHelper.startPage(currentPage,pageSize);
Page<CheckItem> page = checkItemDao.selectByCondition(queryString);
return new PageResult(page.getTotal(),page.getResult());
}
(4)CheckItemDao.java(Dao接口)
(5)CheckItemDao.xml(Mapper映射文件)
<!--条件查询-->
<select id="selectByCondition" parameterType="string" resultType="com.itheima.pojo.CheckItem">
select * from t_checkitem
<if test="value != null and value.length > 0">
where code = #{value} or name = #{value}
</if>
</select>
2. 删除检查项
【分析】
-
需求分析:点击“删除”按钮,发送删除请求。如果检查项跟检查组已经产生关系,则需要提示用户,不能删除已经有关系 反之可以删除
-
数据库表:t_checkitem 删除 t_checkgroup_checkitem:查询
-
编码分析
3.1. 前端编码分析
3.1.1. 点击“删除”按钮,弹出确认提示框,如果用户点击确认,再发送删除请求/checkitem/deleteById.do?checkItemId=xxx get
3.1.2. 成功或失败提示,刷新页面
3.2. 后端编码分析
3.2.1. controller接收请求 Integer checkItemId
3.2.2. controller调用service业务处理
a. 根据检查项id查询检查项检查组中间表 记录是否存在
b.如果关系存在,则提示用户不能删除,已经存在关系
c.如果关系不存在,则删除检查项记录
3.2.3.dao持久层接口 映射
【目标】
删除检查项
【路径】
1:前台代码
(1):绑定删除单击事件
(2):弹出确认操作提示(在ElementUI中查找)
(3):发送ajax请求,执行删除
2:后台代码
(1)CheckItemController.java
(2)CheckItemService.java(服务接口)
(3)CheckItemServiceImpl.java(服务实现类)
(4)CheckItemDao.java(Dao接口)
(5)CheckItemDao.xml(Mapper映射文件)
【讲解】
2.1. 前台代码
为了防止用户误操作,点击删除按钮时需要弹出确认删除的提示,用户点击取消则不做任何操作,用户点击确定按钮再提交删除请求。
2.1.1. 绑定单击事件
需要为删除按钮绑定单击事件,并且将当前行数据作为参数传递给处理函数
<el-button size="mini" type="danger" @click="handleDelete(scope.row)">删除</el-button>
调用的方法
// 删除
handleDelete(row) {
alert(row.id);
}
2.1.2. 弹出确认操作提示
用户点击删除按钮会执行handleDelete方法,此处需要完善handleDelete方法,弹出确认提示信息。ElementUI提供了$confirm方法来实现确认提示信息弹框效果
// 删除
handleDelete(row) {
// alert(row.id);
this.$confirm("确认删除当前选中记录吗?","提示",{type:'warning'}).then(()=>{
//点击确定按钮时只需此处代码
alert('用户点击的是确定按钮');
});
}
2.1.3. 发送请求
如果用户点击确定按钮就需要发送ajax请求,并且将当前检查项的id作为参数提交到后台进行删除操作
handleDelete(row) {
this.$confirm('此操作将永久删除该检查项记录, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
//3.1.1. 点击“删除”按钮,弹出确认提示框,如果用户点击确认,再发送删除请求/checkitem/deleteById.do?checkItemId=xxx get
axios.get("/checkitem/deleteById.do?checkItemId="+row.id).then(res=>{
// 3.1.2. 成功或失败提示,刷新页面
this.$message({
message: res.data.message,
type: res.data.flag ? 'success':'error'
});
//刷新页面
this.findPage();
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
}
}
2.2. 后台代码
2.2.1. Controller
在CheckItemController中增加删除方法
/**
* 删除检查项
*/
@RequestMapping(value = "/deleteById",method = RequestMethod.GET)
public Result deleteById(Integer checkItemId){
//3.2.1. controller接收请求 Integer checkItemId
try {
//3.2.2. controller调用service业务处理
checkItemService.deleteById(checkItemId);
return new Result(true, MessageConstant.DELETE_CHECKITEM_SUCCESS);
} catch (RuntimeException e) {
e.printStackTrace();
return new Result(false, e.getMessage());
} catch (Exception e) {
e.printStackTrace();
return new Result(false, MessageConstant.DELETE_CHECKITEM_FAIL);
}
}
2.2.2. Service服务实现类
在CheckItemService服务接口中扩展删除方法
/**
* 删除检查项
*/
void deleteById(Integer checkItemId);
在CheckItemServiceImpl服务实现类中扩展删除方法实现
注意:不能直接删除,需要判断当前检查项是否和检查组关联,如果已经和检查组进行了关联则不允许删除
/**
* 删除检查项
*/
@Override
public void deleteById(Integer checkItemId) {
//a. 根据检查项id查询检查项检查组中间表 记录是否存在
int count = checkItemDao.selectCountById(checkItemId);
//b.如果关系存在,则提示用户不能删除,已经存在关系
if(count > 0 ){
throw new RuntimeException(MessageConstant.DELETE_ITEM_GROUP_FAIL);
}
//c.如果关系不存在,则删除检查项记录
checkItemDao.deleteById(checkItemId);
}
2.2.3. Dao接口
在CheckItemDao接口中扩展方法findCountByCheckItemId和deleteById
/**
*根据检查项id查询检查项检查组中间表
* @param checkItemId
* @return
*/
int selectCountById(Integer checkItemId);
/**
* 则删除检查项记录
* @param checkItemId
*/
void deleteById(Integer checkItemId);
2.2.4. Mapper映射文件
在CheckItemDao.xml中扩展SQL语句
<!--根据检查项id查询检查项检查组中间表-->
<select id="selectCountById" parameterType="int" resultType="int">
select count(*) from t_checkgroup_checkitem where checkitem_id = #{checkItemId}
</select>
<!--则删除检查项记录-->
<delete id="deleteById" parameterType="int">
delete from t_checkitem where id = #{checkItemId}
</delete>
【小结】
1:前台代码
(1):绑定删除单击事件
(2):弹出确认操作提示
(3):发送ajax请求,执行删除
2:后台代码
(1)CheckItemController.java
(2)CheckItemService.java(服务接口)
(3)CheckItemServiceImpl.java(服务实现类)
(4)CheckItemDao.java(Dao接口)
(5)CheckItemDao.xml(Mapper映射文件)
3. 编辑检查项
【分析】
-
需求分析:点击“编码”按钮,弹出编辑窗口,回显检查项数据。修改检查项数据,点击“提交”按钮发送请求。
-
数据库表:t_checkitem 修改
-
编码分析
3.1. 前端编码分析
3.1.1. 点击“编码”按钮,弹出编辑窗口,根据检查项id发送请求查询检查项数据进行回显
3.1.2. 修改检查项数据,点击“提交”按钮发送请求/checkitem/edit.do post 表单对象
3.1.2. 成功或失败提示,刷新页面
3.2. 后端编码分析
3.2.1. controller接收回显数据请求 编码controller service dao
3.2.2. controller接收编辑检查项请求@RequestBody CheckItem checkItem
3.2.3. controller调用service业务处理
调用dao编辑检查项数据
3.2.3.dao持久层接口 映射
【目标】
1:编辑检查项(ID查询,回显)
2:编辑检查项(更新保存,执行update)
【路径】
1:前台代码
(1):点击编辑按钮,绑定单击事件
(2):弹出编辑窗口回显数据
(3):发送ajax请求,更改数据保存
2:后台代码
(1)CheckItemController.java
- 跳转到检查项编辑页面
- 编辑保存
(2)CheckItemService.java(服务接口)
(3)CheckItemServiceImpl.java(服务实现类)
(4)CheckItemDao.java(Dao接口)
(5)CheckItemDao.xml(Mapper映射文件)
【讲解】
3.1. 前台代码
用户点击编辑按钮时,需要弹出编辑窗口并且将当前记录的数据进行回显,用户修改完成后点击确定按钮将修改后的数据提交到后台进行数据库操作。
3.1.1. 绑定单击事件
需要为编辑按钮绑定单击事件,并且将当前行数据作为参数传递给处理函数
<el-button type="primary" size="mini" @click="handleUpdate(scope.row)">编辑</el-button>
处理事件:handleUpdate();
// 弹出编辑窗口
handleUpdate(row) {
alert(row.id);
},
3.1.2. 弹出编辑窗口回显数据
当前页面中的编辑窗口已经提供好了,默认处于隐藏状态。在handleUpdate方法中需要将编辑窗口展示出来,并且需要发送ajax请求查询当前检查项数据用于回显
// 弹出编辑窗口
handleUpdate(row) {
//3.1.1. 点击“编码”按钮,弹出编辑窗口,根据检查项id发送请求查询检查项数据进行回显
this.dialogFormVisible4Edit = true;
axios.get("/checkitem/findById.do?checkItemId="+row.id).then(res=>{
// 3.1.2. 成功或失败提示,刷新页面
this.$message({
message: res.data.message,
type: res.data.flag ? 'success':'error'
});
this.formData = res.data.data;
})
},
3.1.3. 发送请求更改数据
在编辑窗口中修改完成后,点击确定按钮需要提交请求,所以需要为确定按钮绑定事件并提供处理函数handleEdit
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible4Edit = false">取消</el-button>
<el-button type="primary" @click="handleEdit()">确定</el-button>
</div>
handleEdit()方法
//编辑
handleEdit() {
//3.1.2. 修改检查项数据,点击“提交”按钮发送请求/checkitem/edit.do post 表单对象
axios.post("/checkitem/edit.do",this.formData).then(res=>{
// 3.1.2. 成功或失败提示,刷新页面
this.$message({
message: res.data.message,
type: res.data.flag ? 'success':'error'
});
this.findPage();
this.dialogFormVisible4Edit =false;
})
},
3.2. 后台代码
3.2.1. Controller
在CheckItemController中增加编辑方法
/**
* 根据检查项id查询检查项数据
*/
@RequestMapping(value = "/findById",method = RequestMethod.GET)
public Result findById(Integer checkItemId){
try {
CheckItem checkItem = checkItemService.findById(checkItemId);
return new Result(true, MessageConstant.QUERY_CHECKITEM_SUCCESS,checkItem);
} catch (Exception e) {
e.printStackTrace();
return new Result(false, MessageConstant.QUERY_CHECKITEM_FAIL);
}
}
/**
* 编辑检查项
*/
@RequestMapping(value = "/edit",method = RequestMethod.POST)
public Result edit(@RequestBody CheckItem checkItem){
// 3.2.2. controller接收编辑检查项请求@RequestBody CheckItem checkItem
try {
// 3.2.3. controller调用service业务处理
checkItemService.edit(checkItem);
return new Result(true, MessageConstant.EDIT_CHECKITEM_SUCCESS);
} catch (Exception e) {
e.printStackTrace();
return new Result(false, MessageConstant.EDIT_CHECKITEM_FAIL);
}
}
3.2.2. Service服务实现类
在CheckItemService服务接口中扩展编辑方法
/**
* 根据检查项id查询检查项数据
*/
CheckItem findById(Integer checkItemId);
/**
* 编辑检查项
*/
void edit(CheckItem checkItem);
在CheckItemServiceImpl实现类中实现编辑方法
/**
* 根据检查项id查询检查项数据
*/
@Override
public CheckItem findById(Integer checkItemId) {
return checkItemDao.findById(checkItemId);
}
/**
* 编辑检查项
*/
@Override
public void edit(CheckItem checkItem) {
checkItemDao.edit(checkItem);
}
3.2.3. Dao接口
在CheckItemDao接口中扩展edit方法
/**
* 根据检查项id查询检查项数据
*/
CheckItem findById(Integer checkItemId);
/**
* 编辑检查项
*/
void edit(CheckItem checkItem);
3.2.4. Mapper映射文件
在CheckItemDao.xml中扩展SQL语句
<!--根据检查项id查询检查项数据-->
<select id="findById" parameterType="int" resultType="com.itheima.pojo.CheckItem">
select * from t_checkitem where id = #{checkItemId}
</select>
<!--编辑检查项-->
<update id="edit" parameterType="com.itheima.pojo.CheckItem">
update t_checkitem
<set>
<if test="code != null and code.length>0">
code = #{code},
</if>
<if test="name != null and name.length>0">
name = #{name},
</if>
<if test="sex != null and sex.length>0">
sex = #{sex},
</if>
<if test="age != null and age.length>0">
age = #{age},
</if>
<if test="price != null">
price = #{price},
</if>
<if test="type != null and type.length>0">
type = #{type},
</if>
<if test="remark != null and remark.length>0">
remark = #{remark},
</if>
<if test="attention != null and attention.length>0">
attention = #{attention},
</if>
</set>
where id = #{id}
</update>
【小结】
1:前台代码
(1):点击编辑按钮,绑定单击事件
(2):弹出编辑窗口回显数据
(3):发送ajax请求,更改数据保存
2:后台代码
(1)CheckItemController.java
- 跳转到检查项编辑页面(ID查询)
- 编辑保存
(2)CheckItemService.java(服务接口)
(3)CheckItemServiceImpl.java(服务实现类)
(4)CheckItemDao.java(Dao接口)
(5)CheckItemDao.xml(Mapper映射文件)
在CheckItemDao.xml中扩展SQL语句
<!--根据检查项id查询检查项信息-->
<select id="findCheckItemById" resultType="com.itheima.pojo.CheckItem" parameterType="int">
select * from t_checkitem where id = #{id}
</select>
<!--编辑-->
<update id="edit" parameterType="com.itheima.pojo.CheckItem">
update t_checkitem
<set>
<if test="code!=null and code.length>0">
code=#{code},
</if>
<if test="name!=null and name.length>0">
name=#{name},
</if>
<if test="sex!=null and sex.length>0">
sex=#{sex},
</if>
<if test="age!=null and age.length>0">
age=#{age},
</if>
<if test="price!=null">
price=#{price},
</if>
<if test="type!=null and type.length>0">
type=#{type},
</if>
<if test="remark!=null and remark.length>0">
remark=#{remark},
</if>
<if test="attention!=null and attention.length>0">
attention=#{attention},
</if>
</set>
where id = #{id}
</update>
4. 新增检查组
检查组其实就是多个检查项的集合,例如有一个检查组为“一般检查”,这个检查组可以包括多个检查项:身高、体重、收缩压、舒张压等。所以在添加检查组时需要选择这个检查组包括的检查项。
检查组对应的实体类为CheckGroup,对应的数据表为t_checkgroup。检查组和检查项为多对多关系,所以需要中间表t_checkgroup_checkitem进行关联。
【分析】
-
需求分析:点击“新建”弹出新增检查组窗口,查询所有检查项列表数据,填充检查组数据以及勾选检查项,并点击提交按钮。
-
数据库表:t_checkgroup 新增 t_checkgroup_checkitem 新增
-
编码分析
3.1. 前端编码分析
3.1.1. 点击“新增”弹出窗口,清空表单,查询所有检查项列表数据
3.1.2. 填充表单内容以及勾选检查项,点击提交。校验表单内容(省略。。。)
3.1.3. 校验成功,发送请求 /checkgroup/add.do 参数表单对象 检查项ids POST方式
3.1.4. 得到结果,提示成功或失败 刷新页面 关闭窗口
注意:修改页面代码后,右击重新加载框架
3.2. 后端编码分析
3.2.1. controller service dao 查询所有检查项列表数据
3.2.2. controller接收请求 @RequestBody CheckGroup checkGroup,Integer[] ids
3.2.3.ontroller调用service业务处理
a.保存检查组表
b.获取检查组id
c.将检查组id 跟 检查项id 循环插入中间表
3.2.3.dao持久层接口 映射
【目标】
新增检查组
【路径】
1:前台代码
(1)弹出新增窗口
(2)新增窗口中,动态展示检查项列表
(3)提交请求,执行保存
2:后台代码
执行
- 保存检查组数据
- 保存检查组和检查项中间表数据
(1)CheckGroupController.java(Controller)
(2)CheckGroupService.java(服务接口)
(3)CheckGroupServiceImpl.java(服务实现类)
(4)CheckGroupDao.java(Dao接口)
(5)CheckGroupDao.xml(Mapper映射文件)
【讲解】
4.1. 前台代码
检查组管理页面对应的是checkgroup.html页面,根据产品设计的原型已经完成了页面基本结构的编写,现在需要完善页面动态效果。
4.1.1. 弹出新增窗口
页面中已经提供了新增窗口,只是出于隐藏状态。只需要将控制展示状态的属性dialogFormVisible改为true即可显示出新增窗口。点击新建按钮时绑定的方法为handleCreate,所以在handleCreate方法中修改dialogFormVisible属性的值为true即可。同时为了增加用户体验度,需要每次点击新建按钮时清空表单输入项。
(1)新建按钮绑定单击事件,对应的处理函数为handleCreate
<el-button type="primary" class="butT" @click="handleCreate()">新建</el-button>
(2)handleCreate()方法
// 重置表单
resetForm() {
this.formData = {};
},
// 弹出添加窗口
handleCreate() {
this.resetForm();
this.dialogFormVisible = true;
},
4.1.2. 新增窗口中,动态展示检查项列表
现在虽然已经完成了新增窗口的弹出,但是在检查项信息标签页中需要动态展示所有的检查项信息列表数据,并且可以进行勾选。具体操作步骤如下:
(1)定义模型数据
tableData:[],//新增和编辑表单中对应的检查项列表数据
checkitemIds:[],//新增和编辑表单中检查项对应的复选框,基于双向绑定可以进行回显和数据提交,传递检查项id的数组
(2)动态展示检查项列表数据,数据来源于上面定义的tableData模型数据
<el-tab-pane label="检查项信息" name="second">
<div class="checkScrol">
<table class="datatable">
<thead>
<tr>
<th>选择</th>
<th>项目编码</th>
<th>项目名称</th>
<th>项目说明</th>
</tr>
</thead>
<tbody>
<tr v-for="c in tableData">
<td>
<input :id="c.id" v-model="checkitemIds" type="checkbox" :value="c.id">
</td>
<td><label :for="c.id">{{c.code}}</label></td>
<td><label :for="c.id">{{c.name}}</label></td>
<td><label :for="c.id">{{c.remark}}</label></td>
</tr>
</tbody>
</table>
</div>
</el-tab-pane>
(3)完善handleCreate方法,发送ajax请求查询所有检查项数据并将结果赋值给tableData模型数据用于页面表格展示
// 弹出添加窗口
handleCreate() {
//3.1.1. 点击“新增”弹出窗口,清空表单,查询所有检查项列表数据
this.dialogFormVisible = true;
this.formData = {}; //null 单个值 []展示集合数据 {}展示对象
axios.get("/checkitem/findAll.do").then(res=>{
this.tableData = res.data.data;
this.$message({
message: res.data.message,
type: res.data.flag ? 'success':'error'
});
})
},
(4)分别在CheckItemController、CheckItemService、CheckItemServiceImpl、CheckItemDao、CheckItemDao.xml中扩展方法查询所有检查项数据
【1】:CheckItemController:
/**
* 查询所有检查项列表
*/
@RequestMapping(value = "/findAll",method = RequestMethod.GET)
public Result findAll(){
try {
List<CheckItem> list = checkItemService.findAll();
return new Result(true, MessageConstant.QUERY_CHECKITEM_SUCCESS,list);
} catch (Exception e) {
e.printStackTrace();
return new Result(false, MessageConstant.QUERY_CHECKITEM_FAIL);
}
}
【2】:CheckItemService:
/**
* 查询所有检查项列表
*/
List<CheckItem> findAll();
【3】:CheckItemServiceImpl:
/**
* 查询所有检查项列表
*/
@Override
public List<CheckItem> findAll() {
return checkItemDao.findAll();
}
【4】:CheckItemDao:
/**
* 查询所有检查项列表
*/
List<CheckItem> findAll();
【5】:CheckItemDao.xml:
<select id="findAll" resultType="com.itheima.pojo.CheckItem">
select * from t_checkitem
</select>
4.1.3. 提交请求,执行保存
当用户点击新增窗口中的确定按钮时发送ajax请求将数据提交到后台进行数据库操作。提交到后台的数据分为两部分:检查组基本信息(对应的模型数据为formData)和检查项id数组(对应的模型数据为checkitemIds)。
(1)为确定按钮绑定单击事件,对应的处理函数为handleAdd
<el-button type="primary" @click="handleAdd()">确定</el-button>
(2)完善handleAdd方法
//添加
handleAdd () {c
//3.1.2. 填充表单内容以及勾选检查项,点击提交。校验表单内容(省略。。。)
axios.post("/checkgroup/add.do?checkItemIds="+this.checkitemIds,this.formData).then(res=>{
this.$message({
message: res.data.message,
type: res.data.flag ? 'success':'error'
});
//刷新页面
this.findPage();
//关闭窗口
this.dialogFormVisible = false;
})
},
4.2. 后台代码
4.2.1. Controller
在health_web工程中创建CheckGroupController
package com.itheima.controller;
import com.itheima.constant.MessageConstant;
import com.itheima.entity.Result;
import com.itheima.pojo.CheckGroup;
import com.itheima.service.CheckGroupService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
/**
* 检查组管理控制层
*/
@RestController
@RequestMapping("/checkgroup")
public class CheckGroupController {
@Autowired
private CheckGroupService checkGroupService;
/**
* 新增检查组
*/
@RequestMapping(value = "/add",method = RequestMethod.POST)
public Result add(@RequestBody CheckGroup checkGroup,Integer[] checkItemIds){
try {
checkGroupService.add(checkGroup,checkItemIds);
return new Result(true, MessageConstant.ADD_CHECKGROUP_SUCCESS);
} catch (Exception e) {
e.printStackTrace();
return new Result(false, MessageConstant.ADD_CHECKGROUP_FAIL);
}
}
}
4.2.2. Service服务实现类
在health_service工程中创建CheckGroupService接口
package com.itheima.service;
import com.itheima.pojo.CheckGroup;
/**
* 检查组管理业务层
*/
public interface CheckGroupService {
/**
* 新增检查组
*/
void add(CheckGroup checkGroup,Integer[] checkItemIds);
}
在health_service工程中创建CheckGroupServiceImpl实现类
package com.itheima.service.impl;
import com.itheima.dao.CheckGroupDao;
import com.itheima.pojo.CheckGroup;
import com.itheima.service.CheckGroupService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.HashMap;
import java.util.Map;
/**
* 检查组业务处理接口实现类
*/
@Service
@Transactional
public class CheckGroupServiceImpl implements CheckGroupService {
@Autowired
private CheckGroupDao checkGroupDao;
/**
* 新增检查组
*/
@Override
public void add(CheckGroup checkGroup,Integer[] checkItemIds) {
//a.保存检查组表
checkGroupDao.add(checkGroup);
//b.获取检查组id
Integer groupId = checkGroup.getId();
//c.将检查组id 跟 检查项id 循环插入中间表
setGroupAndItem(groupId,checkItemIds);
}
/**
* 检查组检查项中间表操作
* @param groupId
* @param checkItemIds
*/
private void setGroupAndItem(Integer groupId, Integer[] checkItemIds) {
if(checkItemIds != null && checkItemIds.length>0){
for (Integer checkItemId : checkItemIds) {
Map map = new HashMap();
map.put("groupId",groupId);
map.put("checkItemId",checkItemId);
checkGroupDao.setGroupAndItem(map);
}
}
}
}
上面我们使用Map集合存储多个字段的值
我们也可以不是Map集合,而直接传递2个参数,例如:
//设置检查组合和检查项的关联关系
public void setCheckGroupAndCheckItem(Integer checkGroupId,Integer[] checkitemIds){
if(checkitemIds != null && checkitemIds.length > 0){
for (Integer checkitemId : checkitemIds) {
checkGroupDao.setCheckGroupAndCheckItem(checkGroupId,checkitemId);
}
}
}
4.2.3. Dao接口
在health_dao工程中创建CheckGroupDao接口
package com.itheima.dao;
import com.itheima.pojo.CheckGroup;
import java.util.Map;
/**
* 检查组持久层接口
*/
public interface CheckGroupDao {
/**
* 新增检查组
*/
void add(CheckGroup checkGroup);
/**
* 检查组检查项中间表操作
*/
void setGroupAndItem(Map map);
}
上面我们使用Map集合存储多个字段的值
我们也可以不是Map集合,而直接传递2个参数,例如:
void setCheckGroupAndCheckItem(@Param(value = "checkGroupId") Integer checkGroupId, @Param(value = "checkitemId")Integer checkitemId);
4.2.4. Mapper映射文件
在health_dao工程中创建CheckGroupDao.xml映射文件,需要和CheckGroupDao接口在同一目录下
<?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" >
<mapper namespace="com.itheima.dao.CheckGroupDao">
<!--新增检查组-->
<insert id="add" parameterType="com.itheima.pojo.CheckGroup">
/*resultType="int"返回值类型 order="AFTER"执行插入完成后执行 keyProperty="id" 将获取的id值设置到id属性上*/
<selectKey resultType="int" order="AFTER" keyProperty="id" >
SELECT LAST_INSERT_ID()
</selectKey>
insert into t_checkgroup(code,name,helpCode,sex,remark,attention)
values(#{code},#{name},#{helpCode},#{sex},#{remark},#{attention})
</insert>
<!--检查组检查项中间表操作-->
<insert id="setGroupAndItem" parameterType="map">
insert into t_checkgroup_checkitem(checkgroup_id,checkitem_id) values (#{groupId},#{checkItemId})
</insert>
</mapper>
上面我们使用Map集合存储多个字段的值
我们也可以直接传递2个参数,对应:@Param(value = "checkGroupId") Integer checkGroupId, @Param(value = "checkitemId")Integer checkitemId例如:
<insert id="setCheckGroupAndCheckItem">
insert into t_checkgroup_checkitem(checkgroup_id,checkitem_id)
values
(#{checkGroupId},#{checkitemId})
</insert>
【小结】
1:前台代码
(1)弹出新增窗口
- 使用选项卡
- 选项卡一:检查组信息
- 选项卡二:检查项列表,并提供复选框
(2)新增窗口中,动态展示检查项列表
- 查询所有检查项
(3)提交请求,执行保存
2:后台代码
执行
- 保存检查组数据
- 保存检查组和检查项中间表数据
(1)CheckGroupController.java(Controller)
(2)CheckGroupService.java(服务接口)
(3)CheckGroupServiceImpl.java(服务实现类)
(4)CheckGroupDao.java(Dao接口)
(5)CheckGroupDao.xml(Mapper映射文件)
- 插入检查组的表
- 插入检查组和检查项的中间表
5. 检查组分页
【目标】
检查组查询分页
【路径】
1:前台代码
(1)定义分页相关模型数据
(2)定义分页方法
(3)完善分页方法执行时机(点击“查询”,点击“分页”)
2:后台代码
执行
- 检查组分页查询
(1)CheckGroupController.java(Controller)
(2)CheckGroupService.java(服务接口)
(3)CheckGroupServiceImpl.java(服务实现类)
(4)CheckGroupDao.java(Dao接口)
(5)CheckGroupDao.xml(Mapper映射文件)
【讲解】
5.1. 前台代码
5.1.1. 定义分页相关模型数据
pagination: {//分页相关模型数据
currentPage: 1,//当前页码
pageSize:10,//每页显示的记录数
total:0,//总记录数
queryString:null//查询条件
},
dataList: [],//当前页要展示的分页列表数据
5.1.2. 定义分页方法
在页面中提供了findPage方法用于分页查询,为了能够在checkgroup.html页面加载后直接可以展示分页数据,可以在VUE提供的钩子函数created中调用findPage方法
//钩子函数,VUE对象初始化完成后自动执行
created() {
this.findPage();
},
findPage()方法。
//分页查询
findPage() {
//分页参数
var param = {
currentPage:this.pagination.currentPage,//页码
pageSize:this.pagination.pageSize,//每页显示的记录数
queryString:this.pagination.queryString//查询条件
};
//请求后台
axios.post("/checkgroup/findPage.do",param).then((response)=> {
//为模型数据赋值,基于VUE的双向绑定展示到页面
this.dataList = response.data.rows;//数据集
this.pagination.total = response.data.total;//总记录数
});
},
5.1.3. 完善分页方法执行时机
除了在created钩子函数中调用findPage方法查询分页数据之外,当用户点击查询按钮或者点击分页条中的页码时也需要调用findPage方法重新发起查询请求。
(1)为查询按钮绑定单击事件,调用findPage方法
<el-button @click="handleCurrentChange(1)" class="dalfBut">查询</el-button>
(2)为分页条组件绑定current-change事件,此事件是分页条组件自己定义的事件,当页码改变时触发,对应的处理函数为handleCurrentChange
<div class="pagination-container">
<el-pagination
class="pagiantion"
@current-change="handleCurrentChange"
:current-page="pagination.currentPage"
:page-size="pagination.pageSize"
layout="total, prev, pager, next, jumper"
:total="pagination.total">
</el-pagination>
</div>
(3)定义handleCurrentChange方法
//切换页码
handleCurrentChange(currentPage) {
//currentPage为切换后的页码
this.pagination.currentPage = currentPage;
this.findPage();
},
5.2. 后台代码
5.2.1. Controller
在CheckGroupController中增加分页查询方法
//分页查询
@RequestMapping("/findPage")
public PageResult findPage(@RequestBody QueryPageBean queryPageBean){
// 传递当前页,每页显示的记录数,查询条件
// 响应PageResult,封装总记录数,结果集
PageResult pageResult = checkGroupService.pageQuery(
queryPageBean.getCurrentPage(),
queryPageBean.getPageSize(),
queryPageBean.getQueryString()
);
return pageResult;
}
5.2.2. Service服务实现类
在CheckGroupService服务接口中扩展分页查询方法
PageResult pageQuery(Integer currentPage, Integer pageSize, String queryString);
在CheckGroupServiceImpl服务实现类中实现分页查询方法,基于Mybatis分页助手插件实现分页
public PageResult pageQuery(Integer currentPage, Integer pageSize, String queryString) {
// 使用分页插件PageHelper,设置当前页,每页最多显示的记录数
PageHelper.startPage(currentPage,pageSize);
// 响应分页插件的Page对象
Page<CheckGroup> page = checkGroupDao.selectByCondition(queryString);
return new PageResult(page.getTotal(),page.getResult());
}
或者使用PageInfo对象封装:
// 1:初始化
PageHelper.startPage(currentPage,pageSize);
// 2:定义条件查询
List<CheckGroup> list = checkGroupDao.findPageByCondition(queryString);
// 3:处理成PageHelper支持的javabean
PageInfo<CheckGroup> pageInfo = new PageInfo<>(list);
return new PageResult(pageInfo.getTotal(),pageInfo.getList());
5.2.3. Dao接口
在CheckGroupDao接口中扩展分页查询方法
Page<CheckGroup> selectByCondition(String queryString);
5.2.4. Mapper映射文件
在CheckGroupDao.xml文件中增加SQL定义
<select id="selectByCondition" parameterType="string" resultType="com.itheima.pojo.CheckGroup">
select * from t_checkgroup
<if test="value!=null and value.length>0">
<!-- where code = #{value} or name like '%${value}%' or helpcode = #{value}-->
where code = #{value} or name like concat('%',#{value},'%') or helpcode = #{value}
</if>
</select>
【小结】
1:前台代码
(1)定义分页相关模型数据
(2)定义分页方法findPage()
//分页查询
findPage() {
//分页参数
var param = {
currentPage:this.pagination.currentPage,//页码
pageSize:this.pagination.pageSize,//每页显示的记录数
queryString:this.pagination.queryString//查询条件
};
//请求后台
axios.post("/checkgroup/findPage.do",param).then((response)=> {
//为模型数据赋值,基于VUE的双向绑定展示到页面
this.dataList = response.data.rows;//数据集
this.pagination.total = response.data.total;//总记录数
});
},
(3)完善分页方法执行时机(点击“查询”,点击“分页”)
2:后台代码
- 检查组分页查询
(1)CheckGroupController.java(Controller)
(2)CheckGroupService.java(服务接口)
(3)CheckGroupServiceImpl.java(服务实现类)
(4)CheckGroupDao.java(Dao接口)
(5)CheckGroupDao.xml(Mapper映射文件)
6. 编辑检查组
【分析】
-
需求分析:点击“编辑”按钮,弹出编辑窗口,回显检查组数据、检查项列表数据、勾选检查项 。修改检查组数据以及重新勾选检查项,点击“提交”按钮发送请求。
-
数据库表:t_checkgroup 查询 更新 t_checkgroup_checkitem 查询 先删除再新增
-
编码分析
3.1. 前端编码分析
3.1.1. 点击“编码”按钮,弹出编辑窗口,回显检查组数据、检查项列表数据、勾选检查项
3.1.2. 修改检查组数据以及勾选检查项,点击“提交”按钮发送请求/checkgroup/edit.do post 表单对象 检查项ids
3.1.2. 成功或失败提示,刷新页面 窗口关闭
3.2. 后端编码分析
3.2.1. controller接收回显检查组数据请求 编码controller service dao
3.2.2. controller接收回显勾选检查项请求 编码controller service dao
3.2.3. controller接收编辑检查项请求@RequestBody Checkgroup checkgroup,Integer ids
3.2.4. controller调用service业务处理
a.根据检查组id修改检查组数据
b.根据检查组id删除中间表数据
c.根据检查组id跟检查项ids 往中间表插入数据
3.2.5.dao持久层接口 映射
【目标】
编辑检查组
【路径】
1:前台页面
(1)绑定“编辑”单击事件
(2)弹出编辑窗口回显数据
- 回显检查组数据
- 查询检查项列表
- 当前检查组具有的检查项的复选框需要选中
(3)发送请求,编辑保存检查组
- 编辑检查组
2:后台页面
- 编辑检查组保存
- 删除检查项和检查组中间表数据
- 重新新增检查项和检查组中间表数据
(1)CheckGroupController.java(Controller)
(2)CheckGroupService.java(服务接口)
(3)CheckGroupServiceImpl.java(服务实现类)
(4)CheckGroupDao.java(Dao接口)
(5)CheckGroupDao.xml(Mapper映射文件)
【讲解】
6.1. 前台页面
用户点击编辑按钮时,需要弹出编辑窗口并且将当前记录的数据进行回显,用户修改完成后点击确定按钮将修改后的数据提交到后台进行数据库操作。此处进行数据回显的时候,除了需要检查组基本信息的回显之外,还需要回显当前检查组包含的检查项(以复选框勾选的形式回显)。
6.1.1. 绑定单击事件
(1)需要为编辑按钮绑定单击事件,并且将当前行数据作为参数传递给处理函数
<el-table-column label="操作" align="center">
<template slot-scope="scope">
<el-button type="primary" size="mini" @click="handleUpdate(scope.row)">编辑</el-button>
<el-button size="mini" type="danger" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
(2)handleUpdate事件
// 弹出编辑窗口
handleUpdate(row) {
alert(row.id);
},
6.1.2. 弹出编辑窗口回显数据
当前页面的编辑窗口已经提供好了,默认处于隐藏状态。在handleUpdate方法中需要将编辑窗口展示出来,并且需要发送多个ajax请求分别查询当前检查组数据、所有检查项数据、当前检查组包含的检查项id用于基本数据回显
// 弹出编辑窗口
handleUpdate(row) {
//3.1.1. 点击“编码”按钮,弹出编辑窗口,回显检查组数据、检查项列表数据、勾选检查项
this.dialogFormVisible4Edit = true;
//回显检查组数据
axios.get("/checkgroup/findById.do?groupId="+row.id).then(res=>{
this.$message({
message: res.data.message,
type: res.data.flag ? 'success':'error'
});
if(res.data.flag){//成功 回显数据 并继续发送请求查询
this.formData = res.data.data;
//检查项列表数据
axios.get("/checkitem/findAll.do").then(res=>{
this.$message({
message: res.data.message,
type: res.data.flag ? 'success':'error'
});
if(res.data.flag){
this.tableData = res.data.data;
//勾选检查项
axios.get("/checkgroup/findItemIdsByGroupId.do?groupId="+row.id).then(res=>{
//res.data == List<Integer> [28,29,30]
this.checkitemIds = res.data;
})
}
})
}
})
},
6.1.3. 发送请求,编辑保存检查组
(1)在编辑窗口中修改完成后,点击确定按钮需要提交请求,所以需要为确定按钮绑定事件并提供处理函数handleEdit
<el-button type="primary" @click="handleEdit()">确定</el-button>
(2)handleEdit()方法
//编辑
handleEdit() {
// 3.1.2. 修改检查组数据以及勾选检查项,点击“提交”按钮发送请求/checkgroup/edit.do post 表单对象 检查项ids
axios.post("/checkgroup/edit.do?checkItemIds="+this.checkitemIds,this.formData).then(res=>{
this.$message({
message: res.data.message,
type: res.data.flag ? 'success':'error'
});
//刷新页面
this.findPage();
//关闭窗口
this.dialogFormVisible4Edit = false;
})
},
6.2. 后台代码
6.2.1. Controller
在CheckGroupController中增加方法
/**
* 根据检查组id查询检查组对象
*/
@RequestMapping(value = "/findById",method = RequestMethod.GET)
public Result findById(Integer groupId){
try {
CheckGroup checkGroup = checkGroupService.findById(groupId);
return new Result(true, MessageConstant.QUERY_CHECKGROUP_SUCCESS,checkGroup);
} catch (Exception e) {
e.printStackTrace();
return new Result(false, MessageConstant.QUERY_CHECKGROUP_FAIL);
}
}
/**
* 根据检查组id查询检查项ids
*/
@RequestMapping(value = "/findItemIdsByGroupId",method = RequestMethod.GET)
public List<Integer> findItemIdsByGroupId(Integer groupId){
try {
return checkGroupService.findItemIdsByGroupId(groupId);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 编辑检查组
*/
@RequestMapping(value = "/edit",method = RequestMethod.POST)
public Result edit(@RequestBody CheckGroup checkGroup,Integer[] checkItemIds){
try {
checkGroupService.edit(checkGroup,checkItemIds);
return new Result(true, MessageConstant.EDIT_CHECKGROUP_SUCCESS);
} catch (Exception e) {
e.printStackTrace();
return new Result(false, MessageConstant.EDIT_CHECKGROUP_FAIL);
}
}
6.2.2. Service服务实现类
在CheckGroupService服务接口中扩展方法
/**
* 根据检查组id查询检查组对象
*/
CheckGroup findById(Integer groupId);
/**
* 根据检查组id查询检查项ids
*/
List<Integer> findItemIdsByGroupId(Integer groupId);
/**
* 编辑检查组
*/
void edit(CheckGroup checkGroup, Integer[] checkItemIds);
在CheckGroupServiceImpl实现类中实现编辑方法
/**
* 根据检查组id查询检查组对象
*/
@Override
public CheckGroup findById(Integer groupId) {
return checkGroupDao.findById(groupId);
}
/**
* 根据检查组id查询检查项ids
*/
@Override
public List<Integer> findItemIdsByGroupId(Integer groupId) {
return checkGroupDao.findItemIdsByGroupId(groupId);
}
/**
* 编辑检查组
*/
@Override
public void edit(CheckGroup checkGroup, Integer[] checkItemIds) {
Integer groupId = checkGroup.getId();
//a.根据检查组id修改检查组数据
checkGroupDao.edit(checkGroup);
//b.根据检查组id删除中间表数据
checkGroupDao.deleteByGroupId(groupId);
//c.根据检查组id跟检查项ids 往中间表插入数据
setGroupAndItem(groupId,checkItemIds);
}
6.2.3. Dao接口
在CheckGroupDao接口中扩展方法
/**
* 根据检查组id查询检查组对象
*/
CheckGroup findById(Integer groupId);
/**
* 根据检查组id查询检查项ids
*/
List<Integer> findItemIdsByGroupId(Integer groupId);
/**
*根据检查组id修改检查组数据
* @param checkGroup
*/
void edit(CheckGroup checkGroup);
/**
* 根据检查组id删除中间表数据
* @param groupId
*/
void deleteByGroupId(Integer groupId);
6.2.4. Mapper映射文件
在CheckGroupDao.xml中扩展SQL语句
<!--根据检查组id查询检查组对象-->
<select id="findById" parameterType="int" resultType="com.itheima.pojo.CheckGroup">
select * from t_checkgroup where id = #{groupId}
</select>
<!--根据检查组id查询检查项ids-->
<select id="findItemIdsByGroupId" parameterType="int" resultType="int">
select checkitem_id from t_checkgroup_checkitem where checkgroup_id = #{groupId}
</select>
<!--根据检查组id修改检查组数据-->
<update id="edit" parameterType="com.itheima.pojo.CheckGroup">
update t_checkgroup
<set>
<if test="code != null and code.length>0">
code = #{code},
</if>
<if test="name != null and name.length>0">
name = #{name},
</if>
<if test="helpCode != null and helpCode.length>0">
helpCode = #{helpCode},
</if>
<if test="sex != null and sex.length>0">
sex = #{sex},
</if>
<if test="remark != null and remark.length>0">
remark = #{remark},
</if>
<if test="attention != null and attention.length>0">
attention = #{attention},
</if>
</set>
where id = #{id}
</update>
<!--根据检查组id删除中间表数据-->
<delete id="deleteByGroupId" parameterType="int">
delete from t_checkgroup_checkitem where checkgroup_id = #{groupId}
</delete>
【小结】
1:前台页面
(1)绑定“编辑”单击事件
(2)弹出编辑窗口回显数据
- 回显检查组数据
- 查询检查项列表
- 当前检查组具有的检查项的复选框需要选中
(3)发送请求,编辑保存检查组
- 编辑检查组
2:后台编码
- 编辑检查组保存
- 删除检查项和检查组中间表数据
- 重新新增检查项和检查组中间表数据
(1)CheckGroupController.java(Controller)
(2)CheckGroupService.java(服务接口)
(3)CheckGroupServiceImpl.java(服务实现类)
(4)CheckGroupDao.java(Dao接口)
(5)CheckGroupDao.xml(Mapper映射文件)
7. 图片存储方案
【目标】
传智健康项目,图片存储方案
【路径】
1:介绍
(1)文件上传功能介绍
2:七牛云存储
(1)注册
(2)新建存储空间
(3)查看存储空间信息
(4)开发者中心
- 文件上传
- 文件删除
(5)鉴权
(6)Java SDK操作七牛云
(7)封装工具类
【讲解】
7.1. 介绍
在实际开发中,我们会有很多处理不同功能的服务器。例如:
应用服务器:负责部署我们的应用
数据库服务器:运行我们的数据库
文件服务器:负责存储用户上传文件的服务器
分服务器处理的目的是让服务器各司其职,从而提高我们项目的运行效率。
常见的图片存储方案:
方案一:使用nginx搭建图片服务器
方案二:使用开源的分布式文件存储系统,例如Fastdfs、HDFS等
方案三:使用云存储,例如阿里云、七牛云等
7.2. 七牛云存储
七牛云(隶属于上海七牛信息技术有限公司)是国内领先的以视觉智能和数据智能为核心的企业级云计算服务商,同时也是国内知名智能视频云服务商,累计为 70 多万家企业提供服务,覆盖了国内80%网民。围绕富媒体场景推出了对象存储、融合 CDN 加速、容器云、大数据平台、深度学习平台等产品、并提供一站式智能视频云解决方案。为各行业及应用提供可持续发展的智能视频云生态,帮助企业快速上云,创造更广阔的商业价值。
通过七牛云官网介绍我们可以知道其提供了多种服务,我们主要使用的是七牛云提供的对象存储服务来存储图片。
7.2.1. 注册、登录
要使用七牛云的服务,首先需要注册成为会员。地址:https://portal.qiniu.com/signup
登录成功后点击页面右上角管理控制台:
注意:登录成功后还需要进行实名认证才能进行相关操作。
7.2.2. 新建存储空间
存储空间名称:myhealth119
AK: A_jKJnB1bpEPHn1QdqzPpelrCPU6QfJbJnv-_RR4
SK: CldWf-r2Z6mEkuqQD8zEOVj5U_jIRK-Dcea6T9oB
要进行图片存储,我们需要在七牛云管理控制台新建存储空间。点击管理控制台首页对象存储下的立即添加按钮,页面跳转到新建存储空间页面:
可以创建多个存储空间,各个存储空间是相互独立的。
7.2.3. 查看存储空间信息
存储空间创建后,会在左侧的存储空间列表菜单中展示创建的存储空间名称,点击存储空间名称可以查看当前存储空间的相关信息
课程中重点关注【内容管理】中的信息。
7.2.4. 开发者中心
可以通过七牛云提供的开发者中心学习如何操作七牛云服务,地址:https://developer.qiniu.com/
点击对象存储,跳转到对象存储开发页面,地址:https://developer.qiniu.com/kodo
操作步骤:
第一步:导入jar包:
第二步:鉴权
点击“管理控制台”,点击右上图标
可根据文档中提供的上传文件和删除文件进行测试:
在health_common中测试
7.2.4.1.文件上传
import com.google.gson.Gson;
import com.qiniu.common.QiniuException;
import com.qiniu.common.Zone;
import com.qiniu.http.Response;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.util.Auth;
import org.junit.Test;
public class TestQiniu {
// 上传本地文件
@Test
public void uploadFile(){
//构造一个带指定Zone对象的配置类
Configuration cfg = new Configuration(Zone.zone0());
//...其他参数参考类注释
UploadManager uploadManager = new UploadManager(cfg);
//...生成上传凭证,然后准备上传
String accessKey = "liyKTcQC5TP1LrhgZH6Xem8zqMXbEtVgfAINP53w";
String secretKey = "f5zpuzKAPceEMG77-EK3XbwqgOBRDXDawG4UHRtb";
String bucket = "itcast_health";
//如果是Windows情况下,格式是 D:\\qiniu\\test.png,可支持中文
String localFilePath = "D:/2.jpg";
//默认不指定key的情况下,以文件内容的hash值作为文件名
String key = null;
Auth auth = Auth.create(accessKey, secretKey);
String upToken = auth.uploadToken(bucket);
try {
Response response = uploadManager.put(localFilePath, key, upToken);
//解析上传成功的结果
DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
System.out.println(putRet.key);
System.out.println(putRet.hash);
} catch (QiniuException ex) {
Response r = ex.response;
System.err.println(r.toString());
try {
System.err.println(r.bodyString());
} catch (QiniuException ex2) {
//ignore
}
}
}
}
7.2.4.2.文件删除
// 删除空间中的文件
@Test
public void deleteFile(){
//构造一个带指定Zone对象的配置类
Configuration cfg = new Configuration(Zone.zone0());
//...其他参数参考类注释
String accessKey = "liyKTcQC5TP1LrhgZH6Xem8zqMXbEtVgfAINP53w";
String secretKey = "f5zpuzKAPceEMG77-EK3XbwqgOBRDXDawG4UHRtb";
String bucket = "itcast_health";
String key = "Fu3Ic6TV6wIbJt793yaGeBmCkzTX";
Auth auth = Auth.create(accessKey, secretKey);
BucketManager bucketManager = new BucketManager(auth, cfg);
try {
bucketManager.delete(bucket, key);
} catch (QiniuException ex) {
//如果遇到异常,说明删除失败
System.err.println(ex.code());
System.err.println(ex.response.toString());
}
}
七牛云提供了多种方式操作对象存储服务,本项目采用Java SDK方式,地址:https://developer.qiniu.com/kodo/sdk/1239/java
使用Java SDK操作七牛云需要导入如下maven坐标:(项目已经引入)
<dependency>
<groupId>com.qiniu</groupId>
<artifactId>qiniu-java-sdk</artifactId>
<version>7.2.0</version>
</dependency>
7.2.5. 鉴权
Java SDK的所有的功能,都需要合法的授权。授权凭证的签算需要七牛账号下的一对有效的Access Key和Secret Key,这对密钥可以在七牛云管理控制台的个人中心(https://portal.qiniu.com/user/key)获得,如下图:
7.2.6. Java SDK操作七牛云
本章节我们就需要使用七牛云提供的Java SDK完成图片上传和删除,我们可以参考官方提供的例子。
上传文件:
//构造一个带指定Zone对象的配置类,zone0表示华东地区(默认)
Configuration cfg = new Configuration(Zone.zone0());
//...其他参数参考类注释
UploadManager uploadManager = new UploadManager(cfg);
//...生成上传凭证,然后准备上传
String accessKey = "your access key";
String secretKey = "your secret key";
String bucket = "your bucket name";
//默认不指定key的情况下,以文件内容的hash值作为文件名
String key = null;
try {
byte[] uploadBytes = "hello qiniu cloud".getBytes("utf-8");
ByteArrayInputStream byteInputStream=new ByteArrayInputStream(uploadBytes);
Auth auth = Auth.create(accessKey, secretKey);
String upToken = auth.uploadToken(bucket);
try {
Response response = uploadManager.put(byteInputStream,key,upToken,null, null);
//解析上传成功的结果
DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
System.out.println(putRet.key);
System.out.println(putRet.hash);
} catch (QiniuException ex) {
Response r = ex.response;
System.err.println(r.toString());
try {
System.err.println(r.bodyString());
} catch (QiniuException ex2) {
//ignore
}
}
} catch (UnsupportedEncodingException ex) {
//ignore
}
删除文件:
//构造一个带指定Zone对象的配置类,zone0表示华东地区(默认)
Configuration cfg = new Configuration(Zone.zone0());
//...其他参数参考类注释
String accessKey = "your access key";
String secretKey = "your secret key";
String bucket = "your bucket name";
String key = "your file key";
Auth auth = Auth.create(accessKey, secretKey);
BucketManager bucketManager = new BucketManager(auth, cfg);
try {
bucketManager.delete(bucket, key);
} catch (QiniuException ex) {
//如果遇到异常,说明删除失败
System.err.println(ex.code());
System.err.println(ex.response.toString());
}
7.2.7. 封装工具类
为了方便操作七牛云存储服务,我们可以将官方提供的案例简单改造成一个工具类,在我们的项目中直接使用此工具类来操作就可以:
package com.itheima.utils;
import com.google.gson.Gson;
import com.qiniu.common.QiniuException;
import com.qiniu.common.Zone;
import com.qiniu.http.Response;
import com.qiniu.storage.BucketManager;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.util.Auth;
/**
* 七牛云工具类
*/
public class QiniuUtils {
public static String accessKey = "A_jKJnB1bpEPHn1QdqzPpelrCPU6QfJbJnv-_RR4";
public static String secretKey = "CldWf-r2Z6mEkuqQD8zEOVj5U_jIRK-Dcea6T9oB";
public static String bucket = "myhealth119";
/**
* 本地文件上传
* @param filePath
* @param fileName
*/
public static void upload2Qiniu(String filePath,String fileName){
//构造一个带指定Zone对象的配置类
Configuration cfg = new Configuration(Zone.zone2());
UploadManager uploadManager = new UploadManager(cfg);
Auth auth = Auth.create(accessKey, secretKey);
String upToken = auth.uploadToken(bucket);
try {
Response response = uploadManager.put(filePath, fileName, upToken);
//解析上传成功的结果
DefaultPutRet putRet =
new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
} catch (QiniuException ex) {
Response r = ex.response;
try {
System.err.println(r.bodyString());
} catch (QiniuException ex2) {
//ignore
}
}
}
//上传文件(后续使用)
public static void upload2Qiniu(byte[] bytes, String fileName){
//构造一个带指定Zone对象的配置类
Configuration cfg = new Configuration(Zone.zone2());
//...其他参数参考类注释
UploadManager uploadManager = new UploadManager(cfg);
//默认不指定key的情况下,以文件内容的hash值作为文件名
String key = fileName;
Auth auth = Auth.create(accessKey, secretKey);
String upToken = auth.uploadToken(bucket);
try {
Response response = uploadManager.put(bytes, key, upToken);
//解析上传成功的结果
DefaultPutRet putRet =
new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
System.out.println(putRet.key);
System.out.println(putRet.hash);
} catch (QiniuException ex) {
Response r = ex.response;
System.err.println(r.toString());
try {
System.err.println(r.bodyString());
} catch (QiniuException ex2) {
//ignore
}
}
}
//删除文件(后续使用)
public static void deleteFileFromQiniu(String fileName){
//构造一个带指定Zone对象的配置类
Configuration cfg = new Configuration(Zone.zone2());
String key = fileName;
Auth auth = Auth.create(accessKey, secretKey);
BucketManager bucketManager = new BucketManager(auth, cfg);
try {
bucketManager.delete(bucket, key);
} catch (QiniuException ex) {
//如果遇到异常,说明删除失败
System.err.println(ex.code());
System.err.println(ex.response.toString());
}
}
}
将此工具类放在health_common工程中,后续会使用到。
【小结】
1:介绍
(1)文件上传功能介绍
2:七牛云存储
(1)注册
(2)新建存储空间
(3)查看存储空间信息
(4)开发者中心
(5)鉴权
(6)Java SDK操作七牛云
(7)封装工具类
作业
1.检查组分页思路写一写
2.删除检查组
3.control+alt+shift 双击选择复制 ctrl+c control+alt+shift 双击选择 ctrl+v
扩展-快速定位解决问题90%
前提:保证启动正常,如果启动失败,大概率代码或配置存在问题
前端页面调试
1.Console: 页面js报错信息
2.Sources: 页面源码调试
3.NetWork:请求地址、请求方式、请求参数、状态码、响应结果
后台代码调试
1.controller进入的地方打上断点 请求地址 参数 方式 响应结果是否正确
2.service进入的地方打上断点,单步调试F8 F9(跳到下个断点)
3.dao映射中 id 参数类型 结果类型 sql语句
总结
1.检查组:CRUD
2:检查项:CRUD
【功能分析】
-
需求分析:实现的功能要做出什么样效果?
-
数据库表:功能实现需要操作哪些表?具体做什么操作?条件是什么?
-
编码分析
3.1. 前端编码分析
集合页面原型 一起分析代码实现
3.2. 后端编码分析
接收页面请求 响应结果 业务逻辑处理 操作数据库