Day05

news2024/12/23 7:16:50

目录

1、编写mybatis插件,实现字段自动填充

注意

2、ThreadLocal的简单使用

3、问题:添加员工语句执行成功,但数据库中未添加新员工

4、问题:foreach


1、编写mybatis插件,实现字段自动填充

如何编写插件

@Intercepts({@Signature(type = Executor.class, method = "update",
        args = {MappedStatement.class, Object.class})})
public class MybatisMetaInterceptor implements Interceptor {

    /**
     * invocation存有捕获dao方法的参数,以及sql语句等相关信息<br>
     * 实现自动填充功能
     * @param invocation
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        //获取语句信息
        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
        //获取参数
        Object param = invocation.getArgs()[1];
        //如果dao方法上参数为空,则不进行填充
        if (param == null)
            return invocation.proceed();

        /**
         * 判断参数类型是否为ParamMap
         * 当dao参数为Collection类或者有两个及以上参数时,Mybatis会把参数封装进一个Map中
         *否则,Param的类型就是dao方法上的参数
         */
        if (param instanceof MapperMethod.ParamMap) {
            MapperMethod.ParamMap paramMap = (MapperMethod.ParamMap) param;
            List list = (List) paramMap.get("list");
            List<Field[]> fields = getAllFields(list.get(0));
            list.stream().forEach(item -> {
                try {
                    setValue(mappedStatement, fields, item);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
        } else {
            //单个参数
            List<Field[]> fields = getAllFields(param);
            setValue(mappedStatement, fields, param);
        }

        return invocation.proceed();
    }

    /**
     * 获取参数字段
     * @param param
     * @return
     */
    private List<Field[]> getAllFields(Object param) {
        if (param == null)
            return null;
        ArrayList<Field[]> list = new ArrayList<>();
        Class<?> paramClass = param.getClass();
        while (paramClass != null) {
            list.add(paramClass.getDeclaredFields());
            paramClass = paramClass.getSuperclass();
        }
        return list;
    }

    /**
     * 对对象的字段进行赋值
     * @param mappedStatement
     * @param fields
     * @param param
     * @throws Exception
     */
    private void setValue(MappedStatement mappedStatement, List<Field[]> fields, Object param) throws Exception {
        Long user = BaseThreadLocal.get();
        LocalDateTime time = LocalDateTime.now();
        if (SqlCommandType.INSERT == mappedStatement.getSqlCommandType()) {
            for (Field[] f : fields) {
                for (Field field : f) {
                    field.setAccessible(true);
                    if (field.getName().equals("id")) {
                        field.set(param, YitIdHelper.nextId());
                        log.info(Long.toString((Long) field.get(param)));
                    }

                    if (field.getName().matches("(create|update)User")) {
                        field.set(param, user);
                    }
                    if (field.getName().matches("(create|update)Time")) {
                        field.set(param, time);
                    }

                    field.setAccessible(false);
                }
            }
        }else if (SqlCommandType.UPDATE == mappedStatement.getSqlCommandType()) {
            for (Field[] f : fields) {
                for (Field field : f) {
                    field.setAccessible(true);
                    if (field.getName().matches("updateUser")) {
                        field.set(param, user);
                    }
                    if (field.getName().matches("updateTime")) {
                        field.set(param, time);
                    }
                    field.setAccessible(false);
                }

            }
        }
    }
}

注意

       1、 Invocation.getArgs();会得到一个Object数组,其中的args[0]是MappedStatement对象,存放了被拦截SQL的类型及相关信息。args[1]存放了被拦截方法的参数,首先来看args[1]的类型。

args[1]的类型有两种ParamMap与参数的自身类型,或者null。

当参数个数只有一个且没有@param,并且不是集合类与数组时,我们可以直接强转。

当args[1]返回了ParamMap,我们需要从该Map中获取值,map的key已在图中标出

注意:在Java8及以上,可在JVM启动时添加参数-parameters,这样mybatis可以直接获取到参数名作为key。

2、将自定义拦截器加入mybatis

yaml:

mybatis:
  mapper-locations: classpath:/mapper/*.xml
  configuration:
    interceptors: //全类名

xml:

<plugins>
        <plugin interceptor="org.example.Utils.MybatisMetaInterceptor"/>
    </plugins>

yml的Configuration与xml定制配置,只能用一个

配置类方式加入

@Configuration
public class MyBatisConfig {
  @Bean
  ConfigurationCustomizer mybatisConfigurationCustomizer() {
    return new ConfigurationCustomizer() {
      @Override
      public void customize(Configuration configuration) {
        // customize ...
      }
    };
  }
}

相关文章:MyBatis运行原理(三) : 多参数封装Map的流程、查询实现原理 (源码分析)

                 启用 -parameters 编译选项简化 mybatis @Param 注解重复问题


2、ThreadLocal的简单使用

在看了许多文章后,ThreadLocal的原理应该是这样的:每个Thread内部都有一个Map,当使用threadLocal.set()方法时,会先获取当前线程的Map,在把(threadLocal, value)存入map中。

Threadlocal.get(),则是从当前线程的Map中,获取与threadLocal对应的value

ThreadLocal相当于一个套壳的工具类,本质上还是使用Thread中的Map进行存储。

相关文章

public class BaseThreadLocal {

    private static ThreadLocal<Long> local = new ThreadLocal<>();

    public static Long get() {
        return local.get();
    }

    public static void set(Long v) {
        local.set(v);
    }
}

3、问题:添加员工语句执行成功,但数据库中未添加新员工

表面原因:传给后端的Json对象的Id与数据库中的不一致

根本原因:这个id是Long型,前端解析Long的精度比后端小,当后端传给前端id时,前端会有精度丢失问题

解决:传给前端时,把Long转给String在转给前端

@Configuration
public class WebConfig extends WebMvcConfigurationSupport {


    @Override
    protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        log.info("扩展消息转换器...");
        //创建消息转换器对象
        MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
        //设置对象转换器,底层使用Jackson将Java对象转为json
        messageConverter.setObjectMapper(objectMapper());
        //将上面的消息转换器对象追加到mvc框架的转换器集合中
        converters.add(0,messageConverter);

    }


    private ObjectMapper objectMapper() {
        final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
        ObjectMapper mapper = new ObjectMapper();
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        //添加序列化器
        javaTimeModule.addSerializer(Long.class, ToStringSerializer.instance);
        mapper.registerModule(javaTimeModule);
        return mapper;
    }


}

 注意,以上写法只针对Json对象,当java对象需要转成Json对象时,才会执行上述消息转换器的序列化方法。


4、问题:foreach

相关文章:Java中foreach循环两种实现原理

原理:集合类或者实现了Iterator接口的类的foreach本质上利用了Iterator迭代器

数组的foreach只是把for(var i : arr) ==> for (int i = 0; i < arr.length; i++)的模式

注意点:

 foreach循环不可以改变集合,原因:相关文章

public class Main{
    public static void main(String[] args) throws IOException {
        List<String> list = new ArrayList<>();
        list.add("1");
        list.add("2");
        list.add("3");
        list.add("4");

        for (String s : list) {
            list.remove(s);
        }
    }
}

但是可以改变集合中的对象的属性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/695383.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Jmeter之BeanShell Assertion自定义断言

在JMeter性能测试工具中&#xff0c;BeanShell Assertion是一种强大而灵活的自定义断言方法。 它允许用户通过编写BeanShell脚本来验证服务器返回的响应数据&#xff0c;从而确保系统在各种负载下的稳定性和可靠性。 无论您是初学者还是有经验的专业人士&#xff0c;使用Bean…

Element ui 取消点击空白处弹框关闭的效果

目录 属性&#xff1a; 描述 属性&#xff1a; element组件库的Dialog对话框默认是可以通过点击 modal 关闭 Dialog&#xff0c;即点击空白处弹框可关闭。 描述 在 el-dialog中close-on-click-modal含义是&#xff1a;点击空白处是否关闭&#xff0c;默认true&#xff1b;如…

python实现固定资产梳理的办法

一、需求&#xff1b; 需求&#xff1a;实现xxx地固定资产的计算以及梳理 1.盘点资产&#xff0c;通过excel表格设计了不同的区域&#xff0c;进行每个区域的资产的计数工作&#xff0c;成为了一个登记事项 2.后续形成文本汇报工作&#xff0c;梳理内容 3.需求把表格中同类…

2023金九银十跳槽必会Java核心知识点笔记整理

现在互联网大环境不好&#xff0c;互联网公司纷纷裁员并缩减 HC&#xff0c;更多程序员去竞争更少的就业岗位&#xff0c;整的 IT 行业越来越卷。身为 Java 程序员的我们就更不用说了&#xff0c;上班 8 小时需要做好本职工作&#xff0c;下班后还要不断提升技能、技术栈&#…

沐曦与百度飞桨完成兼容性测试,助力计算机视觉应用发展

近日&#xff0c;沐曦集成电路&#xff08;上海&#xff09;有限公司&#xff08;以下简称“沐曦”&#xff09;的曦思N100人工智能推理GPU与百度飞桨完成 I 级兼容性测试。测试结果显示&#xff0c;双方兼容性表现良好&#xff0c;整体运行稳定。这是沐曦自2022年9月加入“硬件…

五子棋AI智能算法的测试方法

先前发了几篇五子棋游戏程序设计的博文&#xff0c;设计了游戏程序&#xff0c;也设计了AI智能奕棋的算法&#xff0c;运行程序检测算法的可行性&#xff0c;完成人机模式游戏功能的设置。本文重点介绍测试方法。 对于人机对战的电脑智能应子算法&#xff0c;参阅很多五子棋书…

React项目请求接口跨域设置代理怎么设置

在src 目录下创建setupProxy.js const {createProxyMiddleware} require(http-proxy-middleware)module.exports function(app) {app.use(createProxyMiddleware(/api, { //api1是需要转发的请求(所有带有/api1前缀的请求都会转发给5000)target: http://172.20.17.199:808…

学习Kotlin~函数

有名函数 函数参数 不打算传入值参&#xff0c;可以预先给参数指定默认值 //如果不打算传入值参&#xff0c;可以预先给参数指定默认值private fun fix(name: String, age: Int 2) {println(name age);}//调用的时候fix("hhhh");fix("hasee", 30);有名的…

【Html】Html+Less实现一个简单的加载动画

效果 运行环境 系统&#xff1a;Win10系统 IDE&#xff1a;Visual Studio Code v1.79.2 VSCode插件&#xff1a;Easy LESS v2.0.0 index.html代码 <!DOCTYPE html> <html><head><title>加载动画</title><link rel"stylesheet" hr…

Android的Context详解 - 揭开Context的神秘面纱

这篇文章是基于我四年前的一篇文章进行更正和深入探究。背景是&#xff0c;2019年4月份我在找工作&#xff0c;看到一个问题&#xff0c;问this&#xff0c;getBaseContext()、getApplication()、getApplicationContext()的区别。当时我写了简单的demo验证&#xff0c;得出了跟…

看看螯合物前体多肽试剂DOTA-E[c(RGDfK)2]的全面解析吧!

【产品描述】 DOTA-E[c(RGDfK)2]螯合物前体多肽试剂&#xff0c;RGD肽指含有Arg-Gly-Asp三个氨基酸组成的序列多肽&#xff0c;可以提供大量的RGD直线肽&#xff0c;RGD环肽&#xff0c;RGD双环肽、RGD模拟肽等&#xff0c;也可以根据客户需求定制RGD肽。 DOTA-E [c (RGDfK) 2…

6.3 B树

多路平衡查找树 1.定义 B树的阶&#xff1a;B树中所有结点的孩子个数的最大值&#xff0c;表示成m m阶B树&#xff1a;空树或者满足如下特性的m叉树 特性&#xff1a; 1.树中每个结点最多子树 m 关键字m-1 2.根节点不是终端结点&#xff0c;至少有两棵子树 3.根结点除外&…

Java 遍历List的两种方式

可参考文章 Notepad编译并运行java代码_notepad怎么运行java代码_西晋的no1的博客-CSDN博客 中的第二种方法测试下述代码。 在java中&#xff0c;可以使用for循环和使用for-each循环两种方式遍历List。 1.使用for循环遍历List 2.使用for-each遍历List 注意&#xff1a;使用for-…

Java使用Maven工程操作OpenGL ES绘制三角形和圆形;绘制完成后操作键盘控制然图形移动

OpenGL ES 绘制三角形&#xff0c;操作键盘移动位置 PS&#xff1a;想快速看到效果的小伙伴&#xff0c;可以在引入依赖后&#xff0c;先跳到完整代码部分 第一步&#xff1a;依赖引入 <properties><lwjgl.version>3.2.3</lwjgl.version><joml.version&…

mysql 密码丢失的解决方案

问题描述 mysql 密码丢失的解决方案 解决方案&#xff1a; 停止服务; 重新启动服务&#xff1a;mysqld.exe --skip-grant-tables //启动服务器但是跳过权限; 当前启动的服务器没有权限概念&#xff1a;非常危险&#xff0c;任何客户端&#xff0c;不需要任何用户信息都可…

Pycharm连接远端Python环境操作Spark

文章目录 1. 创建工程&#xff0c;指定远端python解析器2. 添加远端python解析器3.配置完成4.本地文件自动同步远端5.删除远端python解析器(非必须操作&#xff0c;重新配置时参考该项)6. 文件模板配置 远程连接方案, 允许程序员连接远端测试环境, 确保环境的统一, 避免各种环境…

消息队列中间件(一)

场景 流量削峰 应用解耦 异步处理 分类 ActiveMQ 优&#xff1a;单机吞吐万级&#xff0c;时效性ms级&#xff0c;可用性高&#xff08;主从架构&#xff09;&#xff0c;可靠性高&#xff08;丢失率低&#xff09; 缺&#xff1a;官方维护少&#xff0c;高吞吐场景较少…

QT Creator上位机学习(二)基础控件及信号与槽

c# 系列文章目录 文章目录 布局控件信号与槽程序图标使用技巧 布局控件 美化界面的时候&#xff0c;经常需要进行一些控件的布局&#xff0c;这时需要使用一些容器类。 在快捷栏出&#xff0c;也有一些布局设计的选择 如上图&#xff0c;其中涉及到几种编辑状态&#xff1…

Math简单学习

1.绝对值 就变个符号 public static double abs(double a) {return (a < 0.0D) ? 0.0D - a : a; }public static float abs(float a) {return (a < 0.0F) ? 0.0F - a : a;}public static int abs(int a) {return (a < 0) ? -a : a;}IntrinsicCandidatepublic sta…

Redis【实战篇】---- 优惠卷秒杀

Redis【实战篇】---- 优惠卷秒杀 1. 全局唯一ID2. Redis实现全局唯一ID3. 添加优惠券4. 实现秒杀哦下单5. 库存超卖问题分析6. 乐观锁解决超卖问题7. 优惠券秒杀 ---- 一人一单8. 集群环境下的并发问题 1. 全局唯一ID 每个店铺都可以发布优惠券&#xff1a; 当用户抢购时&…