【 苍穹外卖 | Day2】

1. 相关视频

Day2的全部视频集数

2. 学习记录

2.1 对象属性拷贝

当DTO与实体类或者VO对象之间的一个装换的时候,如果通过new创建对象,然后调用set方法进行属性赋值,不够方便,代码不够简洁。当属性过多时候,代码就会显得臃肿。所以采用对象属性拷贝。推荐使用MapStruct

java 复制代码
public void save(EmployeeDTO employee){
    BeanUtils.copyProperties(employeeDTO,employee);
}

MapStruct 快速指南 | Baeldung中文网


2.2 分页查询

分页查询,项目经常遇到的功能,本人也学过相关的知识,编写过相关的代码,这里也记录一下

对于分页,可以采取MySQL的limit关键字,但是在实际项目的开发,这样写不够代码的简洁以及提高代码量,工作效率低下,因此还是使用框架来进行分页查询的开发

XML 复制代码
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper-spring-boot-starter</artifactId>
    <version>${pagehelper}</version>
</dependency>

( 对于版本的多少,可以去maven的repository复制,这里主要是作于技术的记录 )

这个插件底层是基于mybatis的拦截器,会将我们的sql语句查询进行一个拼接,动态拼接limit的参数,并且基于参数的计算输出结果

这里使用分页查询插件,最终也还是使用到MySQL的语句进行查询,似乎好像还有其他的框架可以不需要写MySQL语句,直接就是调用就可以返回相关的结果,这个大家可以在评论区讨论

前提准备

java 复制代码
@Data
public class EmployeePageQueryDTO implements Serializable {

    //员工姓名
    private String name;

    //页码
    private int page;

    //每页显示记录数
    private int pageSize;

}


/*----------------------------------------------------------------*/


/**
 * 封装分页查询结果
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PageResult implements Serializable {

    private long total; //总记录数

    private List records; //当前页数据集合

}
java 复制代码
@Service
public class EmployeeServiceImpl implements EmployeeService { 
   /**
     * 分页查询
     *
     * @param pageQueryDTO  分页查询参数
     * @return  分页结果
     */
    @Override
    public PageResult page(EmployeePageQueryDTO pageQueryDTO) {
        // 使用pageHelper分页查询
        PageHelper.startPage(pageQueryDTO.getPage(), pageQueryDTO.getPageSize());

        // 这里需要进行MySQL语句的查询
        Page<Employee> page = employeeMapper.page(pageQueryDTO);

        long total = page.getTotal();
        List<Employee> records = page.getResult();

        return new PageResult(total, records);
    }
}

/*--------------------------------------------------------------------*/

@Mapper
public interface EmployeeMapper {

    /**
     * 分页查询
     * @param pageQueryDTO  分页查询参数
     * @return  分页结果
     */
    Page<Employee> page(EmployeePageQueryDTO pageQueryDTO);
}
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.sky.mapper.EmployeeMapper">
    <select id="page" resultType="com.sky.entity.Employee">
        select * from employee
        <where>
            <if test="name != null and name != ''">
                and name like concat('%', #{name}, '%')
            </if>
        order by crate_time desc
        </where>
    </select>
</mapper>

使用like关键字进行一个模糊查询

友情提醒:mapper文件中的SQL语句不要加分号,否则会报错,因为你加分号之后,limit拼接在之后,就不是正确的mysql语句


3. JWT流程 && ThreadLocal

4. 时间格式处理

推荐使用第二种方式,因为第二种方式是一个统一的配置。如果没有进行一个配置的话,那么返回的是一个集合。另外这里的converters是我们Spring MVC中所有的转换器,并且有顺序排列使用,增加的消息转换器是排在最后,那么为了让我们自定义的转换器优先使用,就需要设置权重

注意:是MappingJackson2HttpMessageConverter,不是MappingJackson2CborHttpMessageConverter,没有Cbor

java 复制代码
/**
 * 对象映射器:基于jackson将Java对象转为json,或者将json转为Java对象
 * 将JSON解析为Java对象的过程称为 [从JSON反序列化Java对象]
 * 从Java对象生成JSON的过程称为 [序列化Java对象到JSON]
 */
public class JacksonObjectMapper extends ObjectMapper {

    public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
    //public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
    public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm";
    public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";

    public JacksonObjectMapper() {
        super();
        //收到未知属性时不报异常
        this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);

        //反序列化时,属性不存在的兼容处理
        this.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

        SimpleModule simpleModule = new SimpleModule()
                .addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
                .addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
                .addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)))
                .addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
                .addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
                .addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));

        //注册功能模块 例如,可以添加自定义序列化器和反序列化器
        this.registerModule(simpleModule);
    }
}

5. 完善苍穹外卖 ------ 密码修改业务

自己完成苍穹外卖的员工密码修改功能

定义传输数据的DTO对象

一开始,看着接口文档还有一个Integer类型的empId,但是经过我后面调试,以及在前端使用f12开启开发者工具,发现前端的请求只有下方两个属性,因此进行修改

java 复制代码
@Data
public class EmployeePasswordDTO {

    private String newPassword;

    private String oldPassword;
}

因为这个业务涉及到如果员工的旧密码输入不对,那么无法进行一个密码的修改,因此需要定义一个常量OLD_PASSWORD_ERROR和将修改方法的类型设计为boolean类型,不是void类型

java 复制代码
/**
 * 信息提示常量类
 */
public class MessageConstant {

    public static final String OLD_PASSWORD_ERROR = "旧密码输入错误";
}
java 复制代码
// Controller层
    /**
     * 修改密码
     * @param passwordDTO  密码DTO
     * @return  修改结果
     */
    @PutMapping("/editPassword")
    @ApiOperation(value = "修改员工密码")
    public Result<String> updatePassword(@RequestBody EmployeePasswordDTO passwordDTO){
        log.info("修改密码:{}", passwordDTO);
        if (!employeeService.updatePassword(passwordDTO))
            return Result.error(MessageConstant.OLD_PASSWORD_ERROR);

        return Result.success();
    }
java 复制代码
// ServiceImpl层
    /**
     * 修改员工密码
     *
     * @param passwordDTO  员工密码信息
     */
    @Override
    public boolean updatePassword(EmployeePasswordDTO passwordDTO) {
        Long empId = BaseContext.getCurrentId();
        Employee employee = employeeMapper.getById(empId);

        String oldPassword = DigestUtils.md5DigestAsHex(passwordDTO.getOldPassword().getBytes());
        if (!employee.getPassword().equals(oldPassword)) {
            return false;
        }

        employee.setPassword(DigestUtils.md5DigestAsHex(passwordDTO.getNewPassword().getBytes()));
        employee.setUpdateTime(LocalDateTime.now());
        employee.setUpdateUser(empId);

        employeeMapper.update(employee);
        return true;
    }

这里ServiceImpl没有做很多解释,有涉及MD5密码的一个不可逆,更新时间以及更新用户的修改,MySQL的修改的语句等这些内容,大家自己看看代码吧,如果是在看不懂,那么评论提出疑问,看到就会即时回复给大家

至于这个继承的接口层就不详细放出,如果这个不会,那么这个博客没有看的必要,先打好基础

相关推荐
爱吃烤鸡翅的酸菜鱼7 小时前
【Spring】原理:Bean的作用域与生命周期
后端·spring
掘根9 小时前
【CMake】缓存变量
java·后端·spring
雾里华11 小时前
Spring AOP深度解析:从实现原理到最佳实践
spring
╭╰40211 小时前
苍穹外卖优化-续
java·spring·mybatis
Dorcas_FE13 小时前
axios请求缓存与重复拦截:“相同请求未完成时,不发起新请求”
前端·spring·缓存
南部余额14 小时前
Spring 基于注解的自动化事务
java·spring·自动化
Mr.Entropy15 小时前
请求超过Spring线程池的最大线程(处理逻辑)
数据库·sql·spring
知其然亦知其所以然16 小时前
三分钟接入!SpringAI 玩转 Perplexity 聊天模型实战
后端·spring·langchain
DKPT1 天前
JVM中如何调优新生代和老生代?
java·jvm·笔记·学习·spring