苍穹外卖-员工分页查询、启用禁用、编辑员工、公共字段填充(二)

Controller
```
@GetMapping(@~"/page")
@Api0peration("员工分页查询")
public Result<PageResult> page(EmployeeQueryDTO employeeDTO){
    log.info("{}分页査询"employeeQueryDTO);
    PageResult pageResult = employeeService.pageQuery(employeeQueryDTO);
    return Result.success(pageResult);
  }

``` 

pagehelper插件
```
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>${pagehelper}</version>
</dependency>
```

```
  @Override
    public PageResult pageQuery(EmployeePageQueryDTO employeePageQueryDTO) {
        //传进去页码,和每页的记录数
        PageHelper.startPage(employeePageQueryDTO.getPage(), employeePageQueryDTO.getPageSize());
        Page<Employee> page = employeeMapper.pageQuery(employeePageQueryDTO);
        long total = page.getTotal();
        List<Employee> records = page.getResult();

        return new PageResult(total,records); 
      
}

```

```
    <select id="pageQuery" resultType="com.sky.entity.Employee">
        select * from employee
        <where>
            <if test="name != '' and name != null">
                and name like concat('%',#{name},'%')
            </if>
        </where>
        order by create_time desc
    </select>
```
第一钟方式注解,日期格式,不建议
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;
第二种扩展springmvc框架的消息转换器

日期格式转换
在server-config下
extendMessageConverters
对后端返回给前端的数据统一进行转换处理
new一个 MappingJackson2HttpMessageConverter()
        converter.setObjectMapper();        //字面意思,对象转换器/new一个传进去
```

    protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        log.info("扩展消息转换器");
        //创建一个消息转换器
        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        //需要为消息转换器设置一个对象转换器,对象转换器可以将Java对象序列化为json数据
        converter.setObjectMapper(new JacksonObjectMapper());
        //将自己的消息转换器加入容器中
        converters.add(0,converter);    //加到首位,优先使用


    }
}
```

启用禁用员工
关于Result返回值的<>泛型,因为查询类操作要返回一个数据data所以泛型加上
非查询类的,泛型就不需要了,就返回code表状态就好了
关于更新修改员工字段status为使得动态sql可以传入不同的参数来修改员工信息
所以需要实现mapper动态语句update的通用性  直接调用mapper的方法并且传参为一个实体类employee
关于@Builder筑建器可以不用new直接取类调用.status()并且属性设置status
所以上述方法和属性是一致的
      Employee employee = Employee.builder().status(status).id(id).build();
    Page<Employee> pageQuery(EmployeePageQueryDTO employeePageQueryDTO);
**【1】悬念1**
在new了新对象employee对象设置了status和id其他属性值为null然而sql语句要根据id查找并且修改其他属性,其他属性不为null的情况下赋值为#{}所以会不会被覆盖
**悬念1解答**在sql赋值语句中,null并不能给属性赋值,故不会被null所覆盖属性值,只修改其他需要修改的属性值

**编辑员工**
编辑员工功能涉及到两个接口:
1.根据id查询员工信息
2.编辑员工信息

导入分类管理功能模块代码
category分类表  分类相关
接口文档存放在apikit分为用户端和管理端
利用swagger框架查看写好的接口信息
这里在移动写好的mvc倒着移文件,先mapper再xml再service最后是controller层,中间还有service的impl不能忽略,是对业务逻辑接口的详细实现方法
当然category的分类相关的六个方法对应的六个接口

**公共字段自动填充**

关于字段创建时间更新时间的修改,持久层(大概是mybatis数据库操作吧)的操作并不是都需要处理,也就是update和insert

使用AOP面向切面统一对公共字段进行处理

-自定义注解 AutoFill,用于标识需要进行公共字段自动填充的方法
-自定义切面类 AutoFillAspect,统一拦截加入了 AutoFill 注解的方法,通过反射为公共字段赋值
-在 Mapper 的方法上加入 AutoFill 注解


**技术点:枚举、注解、AOP、反射**
枚举不同的操作类型(insert、update)
自定义注解,自定义切面,反射:为公共字段进行赋值

总结三步走  (总结面向切面定义公共字段填充的注解分三步)
**一、自定义注解 AutoFill,用于标识需要进行公共字段自动填充的方法**

创建一个annotation包自定义一个注解取名AutoFill用于字段的填充处理(其实就跟创建一个class一样)
标记为  固定写法
```
@Target(ElementType.METHOD) //指定这个注解只能加在方法上面 
@Retention(RetentionPolicy.RUNTIME)
```
在sky-common中的enum已经枚举好数据库操作类型

**总体的注解代码**

```
@Target(ElementType.METHOD) //指定这个注解只能加在方法上面
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {
    //枚举指定数据库操作类型
    OperationType value();

}


```
二、自定义切面类 AutoFillAspect,统一拦截加入了 AutoFill 注解的方法,通过反射为公共字段赋值

创建一个Aspect的切面类就要加Aspect注解,component放入容器里管理也是个bean

@Pointcut()  里面写切入表达式,哪些类的哪些方法进行拦截  execution指定拦截的是什么,返回值是所有的* 拦截的是com.sky.mapper.*.*(..)" @注解为(com.sky.annotation.AutoFill)
两个条件:mapper包下的方法,  必须是上面带autofill注解的方法

在持久层对数据库进行update或者insert操作的时候进行拦截,做一个切点,
而公共字段自动填充的操作写进通知,亦为前置通知,并且指定了切入点方法名,
意味着`切点表达式即将执行,也就是匹配到切点表达式的时候,就进行执行通知方法`
mapper下所有的类所有的方法
```

   @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
    public void autoFillPoinCut(){
  
    }
    
    @Before("autoFillPoinCut()")
    public void autoFill(JoinPoint joinPoint){  //定义参数为joinpoint
          //传进来的参数进行一定的方法操作
        log.info("开始进行公共字段的填充");
    }

```
要想对公共字段进行自动填充, 就需要对mapper文件下的方法进行注解标记为`@AutoFill(value = OperationType.INSERT)`
这里使用到了slf4j的日志打印,loginfo日志用法如同控制台的consolelog和sysout来判断执行
构写自动填充字段方法,首先1、获取操作类型,2、齐次获取被拦截的方法的参数--实体对象。update(Employee)  3、准备好需要赋值的参数的数据
create和update的time和user。time就是当前localtime,而user使用到common下的Context的BaseContext调用getCurrentId获得
4、根据当前不同操作的类型,对相应属性进行反射赋值
比如insert 就需要给createTime、createUser updateTime updateUser进行赋值,而update 就只有update - -

第二步,这里注意因为要获得参数的实体类,对类的属性进行填充,所以约定,自动获取第一个参数args[0]
这里通过获取参数实体类,指定方法名和类型来获取方法
为了防止实体类调用方法的时候,写方法名写错。可以写一个类来存放常量写在了common里的autoFillConstant中,直接将方法名
```

                Method setUpdateTime = entity.getClass().getDeclaredMethod("setUpdateTime", LocalDateTime.class);
                Method setUpdateUser = entity.getClass().getDeclaredMethod("setUpdateUser", Long.class);

```
修改成
```

                Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
   
```
以后都不用修改create和update,直接在方法上加一个注解就可以了

**总体的切面代码**  定义在aspect
```
@Aspect
@Component
@Slf4j
public class AutoFillAspect {

    //切入点
   @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
   //里面写切入表达式,哪些类的哪些方法进行拦截
   //execution指定拦截的是什么,返回值是所有的* 拦截的是com.sky.mapper.*.*(..)"
    public void autoFillPoinCut(){
        
    }
    //定义一个前置通知  因为在执行update之前就要对公共字段进行填充
    //before注解表示前置通知,并且指定为切入点,切点表达式即将执行,也就是匹配到切点表达式的时候,就进行执行方法
    //指定为切点表达式的方法名称 就OK了
    @Before("autoFillPoinCut()")
    //定义参数为joinpoint    参数用于哪个方法被拦截到了,以及被拦截是怎么样的
    public void autoFill(JoinPoint joinPoint){
        log.info("开始进行公共字段的填充");
        //方法签名对象        这里类型转换调用第二个包
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();//获得签名    类型强制转换成子接口Method类型
        AutoFill autofill = signature.getMethod().getAnnotation(AutoFill.class);//获得方法上的注解对象
        OperationType operationType = autofill.value();     //获得数据操作类型
        //1、获取方法操作数据类型
        Object[] args =joinPoint.getArgs();
        if(args == null|| args.length == 0) {
            return;
        }
        Object entity = args[0];
        //2、获取参数
        LocalDateTime now=LocalDateTime.now();
        Long currentId = BaseContext.getCurrentId();
        //3、准备赋值的参数的数据
        if (operationType == OperationType.INSERT){
            //四个公共字段都需要赋值
            try {
                Method setCreateTime =entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME,LocalDateTime.class);
                Method setCreateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
                Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
                //通过反射给对象属性赋值
                setCreateTime.invoke(entity,now);   //刚才已经把这个数据now准备好了
                setCreateUser.invoke(entity,currentId);       //
                setUpdateTime.invoke(entity,now);
                setUpdateUser.invoke(entity,currentId);
            } catch (Exception e) {
                e.printStackTrace();
            }
            
        } else if (operationType == OperationType.UPDATE) {
            //就两个赋值
            //通过这实体类获得class然后获得指定的方法(方法名,需要的参数的类型,)
            try {
                Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
                setUpdateTime.invoke(entity,now);
                setUpdateUser.invoke(entity,currentId);

            } catch (Exception e) {
                e.printStackTrace();
            }

        }
        //4、进行反射
    }
}

```
三、在 Mapper 文件中的update和insert方法上加入 AutoFill 注解
这时可以把CategoryService和EmployeeService中的create和update的赋值都注释掉
```
    @AutoFill(value = OperationType.UPDATE)
    void update(Category category);
```

  

  • 21
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值