项目总体样式如下:
重点功能:模糊条件分页查询功能:
一、前期准备
PageBean实体类:
package com.itheima.pojo;
import java.util.List;
/**
* PageBean: 分页查询功能用来封装数据传递给前端的
*/
public class PageBean<T> { // 这里自定义一个泛型
// 总商品数
private int totalCount;
// 当前页数据 ( 把当前页查询出来的数据以List集合的形式封装到属性当中传递给前端 )
private List<T> rows;
/**
* 这里用自定义的泛型T : 因为以后开发项目的时候 我们有可能有Brand实体类,也有可能有User实体类等。
* 我们自定义好泛型之后,以后谁new 这个PageBean类 这个泛型里面就是谁
*/
// getter and setter
public int getTotalCount() {
return totalCount;
}
public void setTotalCount(int totalCount) {
this.totalCount = totalCount;
}
public List<T> getRows() {
return rows;
}
public void setRows(List<T> rows) {
this.rows = rows;
}
}
二、代码如下
2.1、mapper层 (BrandMapper)
package com.itheima.mapper;
import com.itheima.pojo.Brand;
import org.apache.ibatis.annotations.*;
import java.util.List;
public interface BrandMapper {
/**
* 1、查询所有商品功能
*
*/
@Select("select * from tb_brand")
@ResultMap("brandResultMap")
List<Brand> selectAll();
/**
* 2、添加商品功能
*/
@Insert("insert into tb_brand values (null,#{brandName},#{companyName},#{ordered},#{description},#{status})")
void add(Brand brand);
/**
* 3、批量删除功能
*
* 批量删除:因为我们不知道客户端会传过来几个删除id,因此这里我们要用动态sql 并且不能用注解的形式了
*/
void deleteByIds(int[] ids);
/**
* 4、 查询当前页的数据功能
* 思路: 拿到客户端请求的 ”第几页页数“ 和 “每页展示数据数”,我们拿到之后,再把这页的数据全部查询出来展示给客户端
*/
@Select("select * from tb_brand limit #{begin},#{size}")
@ResultMap("brandResultMap")
List<Brand> selectByPage(@Param("begin") int begin, @Param("size") int size);
/**
* 5、查询数据库商品总数功能
* 把数据库商品的总个数查询出来响应给前端
*/
@Select("select count(*) from tb_brand")
int selectTotalCount();
/**
* 6、分页模糊条件查询功能
*
* 接收前端请求的“页码数”和“每页展示数据数”和“模糊查询的数据请求”(在前端页面看:客户端模糊查询请求的数据只有三个:当前状态、企业名称、品牌名称)
*
* (因为模糊条件查询:比如说客户端就请求了一个企业名称:“阿里巴巴”,但是我们数据库当中会有什么不同的关于“阿里巴巴”的数据,
* 因为是模糊查询所以会查出来很多的数据,前端呢因为怕查询出来的数据太多了所以想分页,所以我们后端接收到前端请求的 “当前页码”,
* “每页展示数据个数” 和“模糊查询的数据” 进行模糊分页查询就可以了
* 就是按一页几条数据来进行查询响应给前端即可了 )
*
*
* begin: 当前页码
* size: 每页展示数据个数
* brand对象: 模糊查询的前端数据请求
*
* 注意:@Param("") 里面的数据对应的是SQL语句的参数占位符 也就是SQL语句中 #{} 内的数据
*
* @return
*/
List<Brand> selectByPageAndCondition(@Param("begin") int begin, @Param("size") int size, @Param("brand") Brand brand);
/**
* 7、查询模糊查询出来的总商品数量功能
* 因为这里面就一个brand对象 所以对象的属性名就相对应着SQL语句的 #{"参数占位数"}
*/
int selectTotalCountByCondition(Brand brand);
}
BrandMapper.xml:
<?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.mapper.BrandMapper">
<resultMap id="brandResultMap" type="brand">
<result property="brandName" column="brand_name" />
<result property="companyName" column="company_name" />
</resultMap>
<delete id="deleteByIds">
delete from tb_brand where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
<!-- where brand_name = #{brand.brandName}-->
<select id="selectByPageAndCondition" resultMap="brandResultMap">
select *
from tb_brand
<where>
<if test="brand.brandName != null and brand.brandName != '' ">
and brand_name like #{brand.brandName}
</if>
<if test="brand.companyName != null and brand.companyName != '' ">
and company_name like #{brand.companyName}
</if>
<if test="brand.status != null">
and status = #{brand.status}
</if>
</where>
limit #{begin} , #{size}
</select>
<select id="selectTotalCountByCondition" resultType="java.lang.Integer">
select count(*)
from tb_brand
<where>
<if test="brandName != null and brandName != '' ">
and brand_name like #{brandName}
</if>
<if test="companyName != null and companyName != '' ">
and company_name like #{companyName}
</if>
<if test="status != null">
and status = #{status}
</if>
</where>
</select>
</mapper>
2.2、service业务逻辑层
BrandService接口:(基本上和代理接口代码是一样的)
package com.itheima.service;
import com.itheima.pojo.Brand;
import com.itheima.pojo.PageBean;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.ResultMap;
import org.apache.ibatis.annotations.Select;
import java.util.List;
public interface BrandService {
/**
* 1、查询所有商品
*
* @return
*/
List<Brand> selectAll();
/**
* 2、添加商品
*
* @param brand
*/
void add(Brand brand);
/**
* 3、批量删除
*/
void deleteByIds(int[] ids);
/**
* 4、查询当前页数据功能 & 查询数据库商品的总个数
*
* @param begin : 当前页数
* @param size : 每一页的展示数据个数
* @return
*/
PageBean<Brand> selectByPage(int begin, int size);
/**
* 6、分页模糊条件查询功能 & 模糊查询出总商品数功能
* @return
*/
PageBean<Brand> selectByPageAndCondition( int begin, int size, Brand brand);
}
BrandServiceImpl:(实现BrandService接口)【该BrandServiceImpl实现了BrandService接口中的所有方法,因为BrandService接口中写的代码逻辑基本上和mapper层的代理接口一样,所以我们在BrandServiceImpl类中做业务逻辑同样相当于以前单独的一个BrandService类中的形式是一样的。】
细节1:使用BrandServiceImpl类实现BrandService接口做业务逻辑作用:降低了service层和web层的耦合度
细节2:所有的逻辑基本上就在业务逻辑层做处理,比如模糊查询需要用到%%,把查询的数据封装到对象属性中等、
package com.itheima.service.impl;
import com.itheima.mapper.BrandMapper;
import com.itheima.pojo.Brand;
import com.itheima.pojo.PageBean;
import com.itheima.service.BrandService;
import com.itheima.util.SqlSessionFactoryUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import java.util.List;
/**
* 用这个类实现接口(BrandService)的最终目的:
* 降低service业务逻辑层和web层的servlet之间的耦合度
*
* 原因: 以前的BrandService类(业务逻辑层)里面是用的方法,把增删改查等全部写成了方法返回到servlet层的
* 现在是把这些增删改查的方法单独写到了实现BrandService接口的这个类当中了,降低了耦合度
*/
public class BrandServiceImpl implements BrandService {
// 1. 创建工厂对象
SqlSessionFactory factory = SqlSessionFactoryUtils.getSqlSessionFactory();
/**
* 1、查询所有商品
*
* @return
*/
@Override
public List<Brand> selectAll() {
// 2. 获取Session
SqlSession sqlSession = factory.openSession();
// 3. 映射出BrandMapper接口
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
// 4. 调用BrandMapper接口中的查询所有的方法
List<Brand> brands = brandMapper.selectAll();
// 释放资源
sqlSession.close();
return brands;
}
/**
* 2、添加商品
*
* @param brand
*/
@Override
public void add(Brand brand) {
// 2. 获取Session
SqlSession sqlSession = factory.openSession();
// 3. 映射出BrandMapper接口
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
// 4. 调用BrandMapper接口中的查询所有的方法
brandMapper.add(brand);
// 5. 提交事务
sqlSession.commit();
// 6. 释放资源
sqlSession.close();
}
/**
* 3、批量删除
*/
@Override
public void deleteByIds(int[] ids) {
// 2. 获取Session
SqlSession sqlSession = factory.openSession();
// 3. 映射出BrandMapper接口
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
// 4. 调用BrandMapper接口中的批量删除的方法
brandMapper.deleteByIds(ids);
// 5. 提交事务
sqlSession.commit();
// 6. 释放资源
sqlSession.close();
}
/**
* 4、查询当前页数据功能 & 查询数据库商品的总个数
*
* 思路: 把查询出来的当前页数据和数据库商品的总个数 封装到PageBean对象的属性当中,然后把PageBean对象返回给前端
*
* @param begin : 当前页数
* @param size : 每一页的展示数据个数
*/
@Override
public PageBean<Brand> selectByPage(int begin,int size) {
// 4.2. 获取Session
SqlSession sqlSession = factory.openSession();
// 4.3. 映射出BrandMapper接口
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
/**
* 重点: 在这里进行一下SQL语句分页查询的计算
* 如: select * from emp limit 0,8; # 计算公式:起始索引(页数)从0开始 起始索引 =(当前查询的页数-1)*每页展示数据数
* 我们拿到的客户端请求的页数是第begin页,那么我们的SQL查询起始索引就是(begin-1)* size
*/
// 4.4、计算起始索引
int begin1 =(begin-1)*size;
// 4.5、计算每页展示的数据个数
int size1 =size;
/**
* 4.6、调用BrandMapper接口的查询当前页数据的功能
*/
List<Brand> brands =brandMapper.selectByPage(begin1,size1);
/**
* 4.7、调用BrandMapper接口的查询数据库商品总数的功能
*/
int totalCount =brandMapper.selectTotalCount();
/**
* 4.8、
* 把 6、7 查询出来的数据封装到PageBean对象的属性当中 返回给前端
*/
PageBean<Brand> pageBean =new PageBean<>();
// 把数据封装到PageBean对象属性当中
pageBean.setRows(brands);
pageBean.setTotalCount(totalCount);
/**
* 4.9、把pageBean对象返回给前端(属性中已经封装好查询出来的数据咯)
*/
sqlSession.close();
return pageBean;
}
/**
* 5、 分页模糊条件查询功能 & 模糊查询出总商品数功能
* @param begin :当前页数
* @param size : 每页中展示的数据数
* @param brand : 模糊条件查询的数据
* @return
*/
@Override
public PageBean<Brand> selectByPageAndCondition(int begin, int size, Brand brand) {
// 5.2. 获取Session
SqlSession sqlSession = factory.openSession();
// 5.3. 映射出BrandMapper接口
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
/**
* 5.4、 调用BrandMapper接口中的 "分页模糊条件查询功能" ( 把模糊查询的结果按分页的形式查询出来,等会响应给前端 )
*
* 注意:这里传参之前要把brand对象当中各属性加上 ”%属性名%“ (因为brand对象属性当中封装了前端模糊查询的请求数据,
* 又因为模糊查询SQL语句是: like %数据% 所以要处理属性)
*
* // !!!! 1、这里要进行一下判断 不判断的话 如果有为null的 那下面模糊处理 就成了 %null% 就会使SQL语句错误了
* // !!!! 2、还要进行分页查询的计算
*/
// 处理模糊表达式
String brandName =brand.getBrandName();
if (brandName!=null && brandName.length() >0){ // 这里要进行一下判断 不判断的话 如果有为null的 那下面模糊处理 就成了 %null% 就会使SQL语句错误了
brand.setBrandName("%" +brandName+ "%"); // 再把客户端请求的数据做一下模糊表达式处理(如:"%华为%")),然后再封装到属性当中 传给代理接口进行SQL语句查询
System.out.println(brand.getBrandName());
}
String companyName =brand.getCompanyName();
if (companyName!=null && companyName.length() >0){ // 不为null 说明前端请求的有值
brand.setCompanyName("%" +companyName+ "%"); // 再把客户端请求的数据做一下模糊表达式处理(如:"%华为%")),然后再封装到属性当中 传给代理接口进行SQL语句查询
}
// 分页计算
int begin1 =(begin-1)*size;
int size1 =size;
List<Brand> brands =brandMapper.selectByPageAndCondition(begin1,size1,brand); // 这里再传的对象属性就是进行过模糊处理的属性数据
/**
* 5.5、 调用BrandMapper接口中的查询 "模糊查询出来的总商品数量" 功能方法 ( 把模糊查询查询出来的总商品数量查询出来,等会响应给前端 )
*/
int counts =brandMapper.selectTotalCountByCondition(brand);
/**
* 5.6、 把 5.4、5.5 查询出来的结果 封装到PageBean对象属性当中,传递响应给前端
*/
PageBean<Brand> pageBean =new PageBean<>();
// 封装数据到属性当中
pageBean.setTotalCount(counts);
pageBean.setRows(brands);
// 释放资源,返回PageBean对象
sqlSession.close();
return pageBean;
}
}
2.3、web层
(使用优化后的servlet。 作用:减少了servlet的个数,以前我们做增删改查的时候就要写增删改查的servlet,需要写4个,太繁琐 ,优化后把每个servlet写成对象方法了 直接调用即可)
可以说因为BsaeServlet继承了HttpServlet,又BrandServlet继承了BsaeServlet,BrandServlet头上又写了访问的路径,所以可以说BrandServlet继承了HttpServlet并自带访问路径地址,可以说和以前的doGet、doPost使用方法又一样了
BsaeServlet:
这个类继承了HttpServlet,能继承service()方法 【可以理解为该方法是doPost,doGet他爹】
package com.itheima.web.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class BaseServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1. 获取请求路径
String url =req.getRequestURI();
// 获取最后一段路径(方法名)
int index =url.lastIndexOf("/"); // 从路径后面数 第一次出现“/”的位置
String methodName =url.substring(index+1); // 获取到从“/”开始截取的后面的路径 (这里我们不要/ 所以+1)
// System.out.println(methodName);
// 2. 执行BrandServlet对象中的selectAll方法
// 2.1 获取BrandServlet 字节码对象 Class (映射)
Class<? extends BaseServlet> cls =this.getClass();
/**
* 注意:这个 this代表的是谁?
* 因为BrandServlet继承了该BaseServlet,所以可以说BrandServlet类当中也有BaseServlet类当中的
* service()方法,当客户端请求路径 @WebServlet("/brand/*") 格式的时候,会进入到BaseServlet资源
* 路径下,会自动调用该service()方法,所以谁调用该方法,this就代表哪个对象
* 因为实际上是BrandServlet类中调用的service()方法 所以this代表BrandServlet对象
*/
// 2.2 获取方法 Method对象(映射)
try {
Method method =cls.getDeclaredMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
// 2.3 调用该方法 (映射)
method.invoke(this,req,resp); // 把客户端的请求数据传到service方法参数中
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
BrandServlet: (继承了BsaeServlet类):
package com.itheima.web.servlet;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.itheima.pojo.Brand;
import com.itheima.pojo.PageBean;
import com.itheima.service.BrandService;
import com.itheima.service.impl.BrandServiceImpl;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.List;
/**
* BrandServlet 继承父类BaseServlet
* 父类中继承了HttpServlet 所以还是相当于BrandServlet继承了HttpServlet
*
* 父类BaseServlet中有service方法 (该方法当客户端访问相对应路径时自动调用该方法中)
* 子类继承了父类 也就是说:这个BrandServlet中实际上也有个service方法 当访问该 @WebServlet("/brand/*")路径时
* 其实调用的是BrandServlet类当中的service()方法
*
*/
@WebServlet("/brand/*")
public class BrandServlet extends BaseServlet{
// 获取业务逻辑层对象
private BrandService brandService =new BrandServiceImpl();
/**
* 1、 查询所有商品功能
*/
public void selectAll(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
// 1. 调用BrandServiceImpl完成查询所有功能
List<Brand> brands =brandService.selectAll();
// 2. 将Java对象数据转换成JSON格式数据,响应给前端
response.setContentType("text/json;charset=utf-8"); // 中文乱码问题
String toString = JSON.toJSONString(brands);
// 3. 响应给前端数据
response.getWriter().write(toString);
}
/**
* 2、 添加商品功能
*/
public void add(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
// 1. 通过抓包拿到前端请求过来的数据(演示的是前端的数据为JSON格式)
BufferedReader bufferedReader =request.getReader();
String rl =bufferedReader.readLine(); // 拿到前端请求的JSON数据
// 2. 将JSON数据转换成Java数据 (也就是说将JSON数据转换成Brand对象类型,将数据封装到对象属性中了)
Brand brand =JSON.parseObject(rl,Brand.class);
// 3. 调用BrandService接口中的添加商品方法
brandService.add(brand);
// 4. 响应给前端success的标识信号
response.getWriter().write("success");
}
/**
* 3、批量删除商品功能
* 思路:把客户端请求的删除id 封装到int数组里面 然后传递给代理接口 供SQL语句使用 (SQL语句要用增强for 遍历该数组删除数据即可)
*/
public void deleteByIds(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException{
// 1、抓包 ( 前端是以JSON数据格式请求数据的,所以需要先抓包 )
BufferedReader bufferedReader =request.getReader();
String params =bufferedReader.readLine();
// System.out.println(params); // 拿到前端请求的JSON数据格式: [1,2,3,4,5]
// 2、把JSON数据转换成Java的数组格式
int[] ids =JSON.parseObject(params,int[].class);
// 3、调用业务逻辑层的批量删除方法 (将数组传到sql语句当中去)
brandService.deleteByIds(ids);
// 4、删除完成后,响应给前端成功的标识
response.getWriter().write("success");
}
/**
* 4、查询当前页码数据功能 & 查询数据库商品的总个数
*/
public void selectByPage(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException{
// 1、接收前端请求过来的 ”当前页码数“ 和 “每页展示的数据个数”
// 假设:前端的访问类型:url?currentPage=1&pageSize=5 (表示:第一页,每一页有五条数据)
// 因为前端不是以JSON格式数据请求的,所以用request域当中的方法就可以获取前端的请求(和doPost doGet方法一样)
String _currentPage =request.getParameter("currentPage");
String _pageSize =request.getParameter("pageSize");
// 2、把String字符串类型转换成int类型
int currentPage =Integer.parseInt(_currentPage);
int pageSize =Integer.parseInt(_pageSize);
// 3、调用查询方法 (把 ”当前页码“ 和 “每页展示的数据个数” 传递过去)
PageBean<Brand> o =brandService.selectByPage(currentPage,pageSize);
// 4. 将Java对象数据转换成JSON格式数据,响应给前端
response.setContentType("text/json;charset=utf-8"); // 中文乱码问题
String toString = JSON.toJSONString(o);
// 5. 响应给前端数据
response.getWriter().write(toString);
}
/**
* 4、分页模糊条件查询功能 & 模糊查询出总商品数功能
*/
public void selectByPageAndCondition(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException{
// 解决POST乱码问题
request.setCharacterEncoding("UTF-8");
// 1、接收前端请求过来的 ”当前页码数“ 和 “每页展示的数据个数” 和”模糊条件查询请求的数据参数“ (模糊条件查询请求的数据参数:前端是以JSON数据请求过来的)
String _currentPage =request.getParameter("currentPage");
String _pageSize =request.getParameter("pageSize");
// 2、把String字符串类型转换成int类型
int currentPage =Integer.parseInt(_currentPage);
int pageSize =Integer.parseInt(_pageSize);
// 3、获取前端模糊条件查询的请求参数
// 3.1、先抓包
BufferedReader bufferedReader =request.getReader();
// 3.2、读一行
String params =bufferedReader.readLine(); // 拿到前端模糊查询请求参数的JSON数据格式
// 3.3、将JSON数据 转换成 Java对象形式
Brand brand =JSON.parseObject(params,Brand.class); // brand对象属性中封装好了前端模糊请求的数据
// 4、 调用 分页模糊条件查询功能
PageBean<Brand> o =brandService.selectByPageAndCondition(currentPage,pageSize,brand);
String jsonString = JSON.toJSONString(o);
// 5、 将查询出来的Java对象数据转换成JSON格式数据,响应给前端
response.setContentType("text/json;charset=utf-8"); // 中文乱码问题
// 6、 响应给前端数据
response.getWriter().write(jsonString);
}
}
其他代码找我要即可~