开始时间:2022-03-07
课程链接:米米商城
Ajax多条件查询
我们把可以看到查询条件有4个
创建一个ProductInfoVO类用于存放这四个参数
package BUPT.pojo.VO;
public class ProductInfoVO {
//商品名称
private String pname;
//商品类型
private Integer typeid;
//最低价格
private Integer lprice;
//最高价格
private Integer hprice;
//getter and setter
//toString();
//constructor
然后写Mapper接口,用于设置多条件查询
接口里
//多条件查询
List<ProductInfo> selectCondition(ProductInfoVO vo);
Mapper配置文件里
<select id="selectCondition" parameterType="BUPT.pojo.VO.ProductInfoVO" resultMap="BaseResultMap">
select
<!-- 为了避免出错,就不用*号了,这里的refid,读取的是所有的字段名-->
<include refid="Base_Column_List"></include>
from product_info
<where>
<if test="pname!=null and pname!=''">
and p_name like '%${pname}%'
</if>
<!--默认复选框不选择时 typeid的值是-1-->
<if test="typeid!=null and typeid!=-1">
and type_id = #{typeid}
</if>
<if test="(lprice!=null and lprice!='') and (hprice==null or hprice=='')">
and p_price >= #{lprice}
</if>
<if test="(hprice!=null and hprice!='') and (lprice==null or lprice=='')">
and p_price <= #{hprice}
</if>
<if test="(hprice!=null and hprice!='') and (lprice!=null and lprice!='')">
<!-- between and都是闭区间-->
and p_price between #{lprice} and #{hprice}
</if>
</where>
order by p_id desc
</select>
这样就把四个框里的数据都读取到了
有多少叠加多少
为了确保我们写的SQL语句没问题
我们需要写一个测试类
package BUPT.Test;
import BUPT.mapper.ProductInfoMapper;
import BUPT.pojo.ProductInfo;
import BUPT.pojo.VO.ProductInfoVO;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
//@RunWith(SpringJUnit4ClassRunner.class),让测试运行于Spring测试环境
@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration : 加载配置文件
@ContextConfiguration(locations = {"classpath:applicationContext_dao.xml", "classpath:applicationContext_service.xml"})
public class MyTest {
@Autowired
ProductInfoMapper mapper;
@Test
public void MyselectCondition() {
ProductInfoVO vo = new ProductInfoVO();
vo.setLprice(500);
vo.setHprice(1700);
List<ProductInfo> list = mapper.selectCondition(vo);
for (ProductInfo pro : list
) {
System.out.println(pro);
}
}
}
我们发现测试没问题,能够实现多条件联合查询
此时我们来完成product.jsp里面功能的实现
在条件搜索框所处的导航栏部分中写上
<div id="condition" style="text-align: center">
<form id="myform">
商品名称:<input name="pname" id="pname">
商品类型:<select name="typeid" id="typeid">
<option value="-1">请选择</option>
<c:forEach items="${typeList}" var="pt">
<option value="${pt.typeId}">${pt.typeName}</option>
</c:forEach>
</select>
价格:<input name="lprice" id="lprice">-<input name="hprice" id="hprice">
<input type="button" value="查询" onclick="condition()">
</form>
</div>
然后补充condition方法
function condition() {
//取出查询条件
var pname = $("#pname").val();
var typeid = $("#typeid").val();
var lprice = $("#lprice").val();
var hprice = $("#hprice").val();
$.ajax({
url: "${pageContext.request.contextPath}/prod/condition.action",
data: {"pname": pname, "typeid": typeid, "lprice": lprice, "hprice": hprice},
type: "post",
success: function () {
//重新加载分页显示的组件table
$("#table").load("http://localhost:8080/mimi_SSM/admin/product.jsp #table");
}
})
}
此时我们进行测试
我们会发现在加载页面中,即使查询了数据,还是没有页面刷新
这是因为我们的 #table标签中,用的是info.list,而不是我们刚刚上传的list
但从控制台的输出信息,我们是能判断已经成功进行了检索
那如果把#table里面的
<c:forEach items="${info.list}" var="p">
改为list,是可以得到检索后的结果,但是这样初始进去的时候是没有显示的,且检索后的结果是不能实现分页的。
为了改善这一情况,我们可以考虑将刚刚设置的vo类,增加分页功能
在ProductInfo类中添加属性
//设置页码
private Integer page = 1;
且进一步的,添加多条件分页查询的接口
PageInfo splitPageVO(ProductInfoVO vo, int PageSize);
以及实现类
@Override
public PageInfo<ProductInfo> splitPageVO(ProductInfoVO vo, int PageSize) {
PageHelper.startPage(vo.getPage(), PageSize);
ProductInfoExample example = new ProductInfoExample();
//设置排序 按主键大小来排
//select * from product_info order by p_id desc;
example.setOrderByClause("p_id desc");
List<ProductInfo> list = productInfoMapper.selectCondition(vo);
//将查到的集合封装金pageInfo对象中
//给了一个list后就封装到pageInfo里面
PageInfo<ProductInfo> pageInfo = new PageInfo<>(list);
return pageInfo;
}
目的在于能把pageInfoVO的信息都传出去
然后书写action
@ResponseBody
@RequestMapping("/condition")
public void condition(ProductInfoVO vo, HttpSession session) {
List<ProductInfo> list = productInfoService.selectCondition(vo);
session.setAttribute("list", list);
}
这样写的话,我们的多条件查询分页还是没有实现
因为Ajax的翻页处理中并没有拿到vo数据
所以需要改造Ajax翻页处理
//Ajax翻页处理
@ResponseBody
@RequestMapping("/ajaxSplit")
public void ajaxSplit(ProductInfoVO vo, HttpSession session) {
PageInfo info = productInfoService.splitPageVO(vo, PAGE_SIZE);
//刷新时session中携带的info
session.setAttribute("info", info);
}
这样在有条件时就出有条件的结果,没有条件时,当做条件为空的有条件结果
那么我们在product.jsp中写的condition函数,就不能再和/condition进行匹配了,而是要和改造后的/ajaxSplit匹配
function condition() {
...
url: "${pageContext.request.contextPath}/prod/ajaxSplit.action",
...
此时进行测试
但是,我们新的问题又来了,在检索了有超过一页数据的情况下
一旦通过导航条跳转了页面,那么他就清空了我们的查询语句,这是因为我们写分页Ajax的时候
function ajaxsplit(page)
传的参数data是一个page,没有带上多条件
我们要对ajaxsplit进行改造
让其带上多参数
function ajaxsplit(page) {
//取出查询条件
var pname = $("#pname").val();
var typeid = $("#typeid").val();
var lprice = $("#lprice").val();
var hprice = $("#hprice").val();
//异步ajax分页请求
$.ajax({
url: "${pageContext.request.contextPath}/prod/ajaxSplit.action",
data: {"page": page, "pname": pname, "typeid": typeid, "lprice": lprice, "hprice": hprice},
type: "post",
success: function () {
//重新加载分页显示的组件table
$("#table").load("http://localhost:8080/mimi_SSM/admin/product.jsp #table");
}
})
};
这样一来就实现了翻页依然保留多条件的查询
如果没有符合条件的商品,我们也要给出一个提示
这也是在我们的table div分块中写好了的
<c:choose>
<c:when test="${info.list.size()!=0}"...>
<c:otherwise>
<div>
<h2 style="width:1200px; text-align: center;color: orangered;margin-top: 100px">暂时没有符合条件的商品!</h2>
</div>
</c:otherwise>
</c:choose>
更新页面拼接条件的提交
当我们查询到结果后,再修改某一个商品的信息,
或者是我们先在第三页停留,查询到信息后,
都会跳转回第一页,这会影响用户体验。
能不能查询之后,之前是第几页,就停留在第几页呢
所以我们应该想到,我们之前刷新页面是走的哪一个方法
@RequestMapping("/split")
public String split(HttpServletRequest request) {
}
这里面我们加载的都是第一页,那我们需要加载到当前页
当前页的信息我们可以在myupdate里面顺着VO对象带过来(放到session里面)vo的getpage是能得到当前的页码
因此写成
//实现编辑功能时能加载该字段所有的数据,进行初始化,实现数据的呈现
@RequestMapping("/myupdate")
public String myshow(int pid, ProductInfoVO vo, HttpServletRequest request, HttpSession session) {
saveFileName = "";
//获取商品信息
ProductInfo info = productInfoService.getByID(pid);
request.setAttribute("prod", info);
//将多条件及页码放入session,更新处理结束后读取条件和页码
session.setAttribute("prodVo", vo);
return "update";
}
接着重写
@RequestMapping("/split")
//显示更新后的当前页的五条记录
@RequestMapping("/split")
public String split(HttpServletRequest request) {
PageInfo info = null;
//拿到VO对象
Object vo = request.getSession().getAttribute("prodVo");
if (vo != null) {
info = productInfoService.splitPageVO((ProductInfoVO) vo, PAGE_SIZE);
//用了就把ProdVo丢了,防止影响后面的数据
request.getSession().removeAttribute("prodVo");
} else {
info = productInfoService.splitPage(1, PAGE_SIZE);
}
//这里setAttribute的name是根据前端来的,统一变量名
request.setAttribute("info", info);
return "product";
}
我们再来完善product.jsp页面
写编辑按钮,我们之前只传了一个pId,这里在补充传上info.pageNum
<td>
<button type="button" class="btn btn-info "
onclick="one(${p.pId},${info.pageNum})">编辑
</button>
<button type="button" class="btn btn-warning" id="mydel"
onclick="del(${p.pId})">删除
</button>
</td>
完善这里的one方法
function one(pid, page) {
//取出查询条件
var pname = $("#pname").val();
var typeid = $("#typeid").val();
var lprice = $("#lprice").val();
var hprice = $("#hprice").val();
//实现,点击”编辑“按钮时,向服务器提交请求,传递商品id,这里的pid是我们前面ProductInfoAction中写的参数名,同时传上VO的几个属性值
var str = "?pid=" + pid + "&page=" + page + "&pname="+pname + "&typeid=" + typeid + "&lprice=" + lprice + "&hprice=" + hprice;
location.href = "${pageContext.request.contextPath}/prod/myupdate.action" + str;
}
现在来看看效果
更新了小米Pro的数量
依然停留在当前页面
同样的,我们想要实现多条件下,多个商品或者单个商品删除后,依然停留在当前页面
删除后停留当前页面
要想停留当前页面,我们还是要先获取到ProductInfoVO对象
那么我们的删除.action,就要有这个值
这个值怎么来的呢?是从product.jsp中携带参数过来的
我们观察到上面编辑更新后停留在当前页面,走的是
<td>
<button type="button" class="btn btn-info "
onclick="one(${p.pId},${info.pageNum})">编辑
</button>
<button type="button" class="btn btn-warning" id="mydel"
onclick="del(${p.pId},${info.pageNum})">删除
</button>
</td>
因此,我们在删除(这里的删除时单页删除)就需要携带info.pageNum
同理,批量删除也是如此
<input type="button" class="btn btn-warning" id="btn1"
value="批量删除" onclick="deleteBatch(${info.pageNum})">
由于补充了这一个参数,因此要更新好对应的方法,注意传的data要把那几个多条件添加进去
单页删除
function del(pid, page) {
if (confirm("您确定删除吗?")) {
//取出查询条件
var pname = $("#pname").val();
var typeid = $("#typeid").val();
var lprice = $("#lprice").val();
var hprice = $("#hprice").val();
$.ajax({
url: "${pageContext.request.contextPath}/prod/delete.action",
type: "post",
data: {"pid": pid, "page": page, "pname": pname, "typeid": typeid, "lprice": lprice, "hprice": hprice},
dataType: "text",
success: function (msg) {
alert(msg);
$("#table").load("http://localhost:8080/mimi_SSM/admin/product.jsp #table")
}
})
}
}
批量删除
//批量删除
function deleteBatch(page) {
//取得所有被选中删除商品的pid
var deleteBatchChecks = $("input[name=ck]:checked");
var str = "";
var pid = "";
if (deleteBatchChecks.length == 0) {
alert("请选择将要删除的商品!");
} else {
// 有选中的商品,则取出每个选 中商品的ID,拼提交的ID的数据
if (confirm("您确定删除" + deleteBatchChecks.length + "条商品吗?")) {
//取出查询条件
var pname = $("#pname").val();
var typeid = $("#typeid").val();
var lprice = $("#lprice").val();
var hprice = $("#hprice").val();
//拼接ID
$.each(deleteBatchChecks, function () {
pid = $(this).val(); //22 33
//进行非空判断
if (pid != null)
str += pid + ","; //22,33,44,
//这里的拼接不影响后面,因为传过去转为数据的时候
//是转成[22,33,44]的
});
$.ajax({
url: "${pageContext.request.contextPath}/prod/deleteBatch.action",
//拼好的主键id
data: {
"pids": str,
"pid": pid,
"page": page,
"pname": pname,
"typeid": typeid,
"lprice": lprice,
"hprice": hprice
},
type: "post",
dataType: "text",
success: function (msg) {
alert(msg);
$("#table").load("http://localhost:8080/mimi_SSM/admin/product.jsp #table")
}
})
}
}
}
由于无论是单页删除还是批量删除,都会走
"/deleteAjaxSplit"
这一个action,那么我们就可以改造他使其能处理ProductInfoVO对象
//加了这个注解,表示最后要从这里进行返回
@ResponseBody
@RequestMapping(value = "/deleteAjaxSplit", produces = "text/html;charset=UTF-8")
public Object deleteAjaxSplit(HttpServletRequest request) {
PageInfo pageInfo = null;
Object vo = request.getSession().getAttribute("deleteProdVO");
//取得当前页的数据,删除后返回到当前页
if (vo != null) {
pageInfo = productInfoService.splitPageVO((ProductInfoVO) vo, PAGE_SIZE);
request.getSession().removeAttribute("deleteProdVO");
} else {
pageInfo = productInfoService.splitPage(1, PAGE_SIZE);
}
request.getSession().setAttribute("info", pageInfo);
return request.getAttribute("msg");
}
而传过去,又得通过各自的action
单个删除
@RequestMapping("/delete")
public String delete(int pid, ProductInfoVO vo, HttpServletRequest request) {
int num = -1;
try {
num = productInfoService.delete(pid);
} catch (Exception e) {
e.printStackTrace();
}
if (num > 0) {
request.setAttribute("msg", "删除成功");
//删除成功才需要跳转到删除后的分页
request.getSession().setAttribute("deleteProdVO", vo);
} else {
request.setAttribute("msg", "删除失败");
}
//删除结束后跳到分页显示
return "forward:/prod/deleteAjaxSplit.action";
}
批量删除
@RequestMapping("/deleteBatch")
public String deleteBatch(String pids, ProductInfoVO vo,HttpServletRequest request) {
String[] ps = pids.split(",");
try {
//将字符串转为字符数组,再放进批量删除方法里面
int num = productInfoService.deleteBatch(ps);
if (num > 0) {
request.setAttribute("msg", "批量删除成功");
//删除成功才需要跳转到删除后的分页
request.getSession().setAttribute("deleteProdVO", vo);
} else {
request.setAttribute("msg", "批量删除失败");
}
} catch (Exception e) {
request.setAttribute("msg", "当前商品不可删除");
}
return "forward:/prod/deleteAjaxSplit.action";
}
测试一下
批量删除
单个删除
结束时间:2022-03-08