0


【SpringBoot篇】分页查询 | 扩展SpringMvc的消息转换器

文章目录

在这里插入图片描述
做了几个项目,发现在这几个项目里面,都实现了

分页查询

效果,所以就总结一下,方便学习

我们

基于黑马程序员的苍穹外卖

来讲解分页查询的要点

🛸什么是分页查询

分页查询是指将大量数据按照固定大小的页进行切分,每次查询只返回一页数据,通过不断翻页来获取全部数据。

🌹代码实现

Result.java

这是一个common类,好多方法都可以使用

packagecom.sky.result;importlombok.Data;importjava.io.Serializable;/**
 * 后端统一返回结果
 * @param <T>
 */@DatapublicclassResult<T>implementsSerializable{privateInteger code;//编码:1成功,0和其它数字为失败privateString msg;//错误信息privateT data;//数据publicstatic<T>Result<T>success(){Result<T> result =newResult<T>();
        result.code =1;return result;}publicstatic<T>Result<T>success(T object){Result<T> result =newResult<T>();
        result.data = object;
        result.code =1;return result;}publicstatic<T>Result<T>error(String msg){Result result =newResult();
        result.msg = msg;
        result.code =0;return result;}}

所有的分页查询,我们都统一封装为

PageResult对象,来表示分页查询结果

PageResult.java

packagecom.sky.result;importlombok.AllArgsConstructor;importlombok.Data;importlombok.NoArgsConstructor;importjava.io.Serializable;importjava.util.List;/**
 * 封装分页查询结果
 */@Data@AllArgsConstructor@NoArgsConstructorpublicclassPageResultimplementsSerializable{privatelong total;//总记录数privateList records;//当前页数据集合}

EmployeeController.java

请添加图片描述

我们查看接口文档,发现接口路径是GET方式,并且请求参数是query,不是json,那么就不需要使用注解@ResponseBody了

packagecom.sky.controller.admin;importcom.sky.constant.JwtClaimsConstant;importcom.sky.dto.EmployeeDTO;importcom.sky.dto.EmployeeLoginDTO;importcom.sky.dto.EmployeePageQueryDTO;importcom.sky.entity.Employee;importcom.sky.properties.JwtProperties;importcom.sky.result.PageResult;importcom.sky.result.Result;importcom.sky.service.EmployeeService;importcom.sky.utils.JwtUtil;importcom.sky.vo.EmployeeLoginVO;importio.swagger.annotations.ApiOperation;importlombok.extern.slf4j.Slf4j;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.web.bind.annotation.*;importjava.util.HashMap;importjava.util.Map;/**
 * 员工管理
 */@RestController@RequestMapping("/admin/employee")@Slf4jpublicclassEmployeeController{@AutowiredprivateEmployeeService employeeService;//    @Autowired//    private JwtProperties jwtProperties;////    /**//     * 登录//     *//     * @param employeeLoginDTO//     * @return//     *///    @PostMapping("/login")//    public Result<EmployeeLoginVO> login(@RequestBody EmployeeLoginDTO employeeLoginDTO) {//        log.info("员工登录:{}", employeeLoginDTO);////        Employee employee = employeeService.login(employeeLoginDTO);////        //登录成功后,生成jwt令牌//        Map<String, Object> claims = new HashMap<>();//        claims.put(JwtClaimsConstant.EMP_ID, employee.getId());//        String token = JwtUtil.createJWT(//                jwtProperties.getAdminSecretKey(),//                jwtProperties.getAdminTtl(),//                claims);////        EmployeeLoginVO employeeLoginVO = EmployeeLoginVO.builder()//                .id(employee.getId())//                .userName(employee.getUsername())//                .name(employee.getName())//                .token(token)//                .build();////        return Result.success(employeeLoginVO);//    }////    /**//     * 退出//     *//     * @return//     *///    @PostMapping("/logout")//    public Result<String> logout() {//        return Result.success();//    }////    @PostMapping//    @ApiOperation("新增员工")//    public Result save(@RequestBody EmployeeDTO employeeDTO){//        log.info("新增员工:{}",employeeDTO);//        return Result.success();//    }@GetMapping("/page")@ApiOperation("员工分页查询")publicResult<PageResult>page(EmployeePageQueryDTO employeePageQueryDTO){
        log.info("员工分页查询,参数为{}",employeePageQueryDTO);PageResult pageResult = employeeService.pageQuery(employeePageQueryDTO);//返回给Result//返回的对象是pageResultreturnResult.success(pageResult);}}

注意,结果return的是Result.success(pageResult);
结果返回的是pageResult对象

在service层扩展一下分页查询方法

这里pageQuery会报错,我们再一个分页查询接口EmployeeService中完善这个方法

EmployeeService.java

packagecom.sky.service;importcom.sky.dto.EmployeeDTO;importcom.sky.dto.EmployeeLoginDTO;importcom.sky.dto.EmployeePageQueryDTO;importcom.sky.entity.Employee;importcom.sky.result.PageResult;publicinterfaceEmployeeService{//Employee login(EmployeeLoginDTO employeeLoginDTO);//void save(EmployeeDTO employeeDTO);//分页查询PageResultpageQuery(EmployeePageQueryDTO employeePageQueryDTO);}

实现这个接口

EmployeeServiceImpl.java

packagecom.sky.service.impl;importcom.github.pagehelper.Page;importcom.github.pagehelper.PageHelper;importcom.sky.constant.MessageConstant;importcom.sky.constant.PasswordConstant;importcom.sky.constant.StatusConstant;importcom.sky.context.BaseContext;importcom.sky.dto.EmployeeDTO;importcom.sky.dto.EmployeeLoginDTO;importcom.sky.dto.EmployeePageQueryDTO;importcom.sky.entity.Employee;importcom.sky.exception.AccountLockedException;importcom.sky.exception.AccountNotFoundException;importcom.sky.exception.PasswordErrorException;importcom.sky.mapper.EmployeeMapper;importcom.sky.result.PageResult;importcom.sky.service.EmployeeService;importorg.springframework.beans.BeanUtils;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Service;importorg.springframework.util.DigestUtils;importjava.time.LocalDateTime;importjava.util.List;@ServicepublicclassEmployeeServiceImplimplementsEmployeeService{@AutowiredprivateEmployeeMapper employeeMapper;/**
     * 员工登录
     *
     * @param employeeLoginDTO
     * @return
     *///    public Employee login(EmployeeLoginDTO employeeLoginDTO) {//        String username = employeeLoginDTO.getUsername();//        String password = employeeLoginDTO.getPassword();////        //1、根据用户名查询数据库中的数据//        Employee employee = employeeMapper.getByUsername(username);////        //2、处理各种异常情况(用户名不存在、密码不对、账号被锁定)//        if (employee == null) {//            //账号不存在//            throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND);//        }////        //密码比对//        // TODO 后期需要进行md5加密,然后再进行比对//        if (!password.equals(employee.getPassword())) {//            //密码错误//            throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR);//        }////        if (employee.getStatus() == StatusConstant.DISABLE) {//            //账号被锁定//            throw new AccountLockedException(MessageConstant.ACCOUNT_LOCKED);//        }////        //3、返回实体对象//        return employee;//    }////    @Override//    public void save(EmployeeDTO employeeDTO) {//        Employee employee=new Employee();////       //对象属性拷贝//        BeanUtils.copyProperties(employeeDTO,employee);////        //设置账号状态,默认正常状态//        employee.setStatus(StatusConstant.ENABLE);////        //设置密码//        //默认密码为123456//        employee.setPassword(DigestUtils.md5DigestAsHex(PasswordConstant.DEFAULT_PASSWORD.getBytes()));////        //设置当前记录的创建时间和修改时间//        employee.setCreateTime(LocalDateTime.now());//        employee.setUpdateTime(LocalDateTime.now());////        //设置当前记录创建人的id和修改人id//        employee.setCreateUser(BaseContext.getCurrentId());//        employee.setUpdateUser(BaseContext.getCurrentId());////        employeeMapper.insert(employee);//    }//分页查询publicPageResultpageQuery(EmployeePageQueryDTO employeePageQueryDTO){PageHelper.startPage(employeePageQueryDTO.getPage(),employeePageQueryDTO.getPageSize());Page<Employee> page=employeeMapper.pageQuery(employeePageQueryDTO);long total=page.getTotal();List<Employee> records=page.getResult();returnnewPageResult(total,records);}}

在这里插入图片描述

这里我们使用了Mybatis的pagehelper插件
要使用这个插件,实现我们在pox.xml文件中导入下面的依赖

<dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId></dependency>

使用这个插件,会把我们后面的sql语句进行动态拼接。类似于MySQL的动态sql,会动态的把limit关键字拼接进去,并且进行动态计算


同理,这里pageQuery会报错,我们在接口DishMapper中完善这个方法

packagecom.sky.mapper;importcom.github.pagehelper.Page;importcom.sky.annotation.AutoFill;importcom.sky.dto.DishPageQueryDTO;importcom.sky.entity.Dish;importcom.sky.enumeration.OperationType;importcom.sky.vo.DishVO;importorg.apache.ibatis.annotations.Mapper;importorg.apache.ibatis.annotations.Select;importorg.springframework.beans.factory.annotation.Autowired;@MapperpublicinterfaceDishMapper{/**
     * 根据分类id查询菜品数量
     * @param 
     * @return
     *///    @Select("select count(id) from dish where category_id = #{categoryId}")//    Integer countByCategoryId(Long categoryId);//////    //插入菜品数据//    @AutoFill(value = OperationType.INSERT)//    void insert(Dish dish);//菜品分页查询Page<DishVO>pageQuery(DishPageQueryDTO dishPageQueryDTO);}

注意
这里我们传入的是DishPageQueryDTO,我们看一下下图
在这里插入图片描述

下面我们来

编写动态sql

对于动态sql,使用注解进行开发是比较麻烦的(因为我们要使用到动态标签),所以我们把这段sql写到xml映射文件中

EmployeeMapper.xml

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPEmapperPUBLIC"-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mappernamespace="com.sky.mapper.EmployeeMapper"><selectid="pageQuery"resultType="com.sky.entity.Employee">
        select * from employee
        <where><iftest="name!=null and name!=''">
--             动态拼接
                and name like concat('%',#{name},'%')
            </if></where>
        order by create_time desc
    </select></mapper>

⭐问题

我们发现,界面展示的时间不是我们想要的 年–月–日,而是一大串数字,我们应该怎么解决呢
请添加图片描述
使用下面的方法进行解决

🎄解决方法

在WebMvcConfiguration中扩展SpringMvc的消息转换器,统一对日期类型进行格式化处理

WebMvcConfiguration.java

packagecom.sky.config;importcom.sky.interceptor.JwtTokenAdminInterceptor;importcom.sky.json.JacksonObjectMapper;importlombok.extern.slf4j.Slf4j;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.http.converter.HttpMessageConverter;importorg.springframework.http.converter.json.MappingJackson2HttpMessageConverter;importorg.springframework.web.servlet.config.annotation.InterceptorRegistry;importorg.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;importorg.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;importspringfox.documentation.builders.ApiInfoBuilder;importspringfox.documentation.builders.PathSelectors;importspringfox.documentation.builders.RequestHandlerSelectors;importspringfox.documentation.service.ApiInfo;importspringfox.documentation.spi.DocumentationType;importspringfox.documentation.spring.web.plugins.Docket;importjava.util.List;/**
 * 配置类,注册web层相关组件
 */@Configuration@Slf4jpublicclassWebMvcConfigurationextendsWebMvcConfigurationSupport{@AutowiredprivateJwtTokenAdminInterceptor jwtTokenAdminInterceptor;////    /**//     * 注册自定义拦截器//     *//     * @param registry//     *///    protected void addInterceptors(InterceptorRegistry registry) {//        log.info("开始注册自定义拦截器...");//        registry.addInterceptor(jwtTokenAdminInterceptor)//                .addPathPatterns("/admin/**")//                .excludePathPatterns("/admin/employee/login");//    }////    /**//     * 通过knife4j生成接口文档//     * @return//     *///    @Bean//    public Docket docket() {//        ApiInfo apiInfo = new ApiInfoBuilder()//                .title("苍穹外卖项目接口文档")//                .version("2.0")//                .description("苍穹外卖项目接口文档")//                .build();//        Docket docket = new Docket(DocumentationType.SWAGGER_2)//                .apiInfo(apiInfo)//                .select()//                .apis(RequestHandlerSelectors.basePackage("com.sky.controller"))//                .paths(PathSelectors.any())//                .build();//        return docket;//    }////    /**//     * 设置静态资源映射//     * @param registry//     *///    protected void addResourceHandlers(ResourceHandlerRegistry registry) {//        registry.addResourceHandler("/doc.html").addResourceLocations("classpath:/META-INF/resources/");//        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");//    }//    //扩展springmvc的消息转换器protectedvoidextendMessageConverters(List<HttpMessageConverter<?>> converters){
        log.info("扩展消息转换器");//创建一个消息转换器对象MappingJackson2HttpMessageConverter converter=newMappingJackson2HttpMessageConverter();//需要为消息转换器设置一个对象转换器,对象转换器可以将Java对象转换为json数据
        converter.setObjectMapper(newJacksonObjectMapper());//将自己的消息转换器加入到容器里面
        converters.add(0,converter);}}
序列化

:从Java对象生成json的过程

反序列化

:把json解析为Java对象的过程


在上一段代码中,我们使用了对象转换器,但是我们应该怎么创建一个对象转换器呢
创建对象转换器

JacksonObjectMapper.java

下面的代码都是比较固定的
packagecom.sky.json;importcom.fasterxml.jackson.databind.DeserializationFeature;importcom.fasterxml.jackson.databind.ObjectMapper;importcom.fasterxml.jackson.databind.module.SimpleModule;importcom.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;importcom.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;importcom.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;importcom.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;importcom.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;importcom.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;importjava.time.LocalDate;importjava.time.LocalDateTime;importjava.time.LocalTime;importjava.time.format.DateTimeFormatter;importstaticcom.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;/**
 * 对象映射器:基于jackson将Java对象转为json,或者将json转为Java对象
 * 将JSON解析为Java对象的过程称为 [从JSON反序列化Java对象]
 * 从Java对象生成JSON的过程称为 [序列化Java对象到JSON]
 */publicclassJacksonObjectMapperextendsObjectMapper{publicstaticfinalStringDEFAULT_DATE_FORMAT="yyyy-MM-dd";//public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";publicstaticfinalStringDEFAULT_DATE_TIME_FORMAT="yyyy-MM-dd HH:mm";publicstaticfinalStringDEFAULT_TIME_FORMAT="HH:mm:ss";publicJacksonObjectMapper(){super();//收到未知属性时不报异常this.configure(FAIL_ON_UNKNOWN_PROPERTIES,false);//反序列化时,属性不存在的兼容处理this.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);SimpleModule simpleModule =newSimpleModule().addDeserializer(LocalDateTime.class,newLocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT))).addDeserializer(LocalDate.class,newLocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT))).addDeserializer(LocalTime.class,newLocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT))).addSerializer(LocalDateTime.class,newLocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT))).addSerializer(LocalDate.class,newLocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT))).addSerializer(LocalTime.class,newLocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));//注册功能模块 例如,可以添加自定义序列化器和反序列化器this.registerModule(simpleModule);}}

这样子就实现了分页查询效果

在这里插入图片描述


本文转载自: https://blog.csdn.net/m0_72853403/article/details/134442700
版权归原作者 在下小吉. 所有, 如有侵权,请联系我们删除。

“【SpringBoot篇】分页查询 | 扩展SpringMvc的消息转换器”的评论:

还没有评论