经过了昨天纠结技术选型,和一大堆xml配置,终于把架子搭好了。因为最近一次做java项目也在好多年以前了(毕竟用了pytohn以后谁也不想再回来java了),java的生态发生了长足的进步,本来想从原来的项目里面拿过来一些,发现除了java还剩下一点兼容性,其他的基本都淘汰了。太悲剧了!连个轮子都没。边学边做吧!好在几个月前又背了一次java课,虽然一些新技术看文档还能应付。spring虽然有改变但是也不大,mybatis也还能凑合用。开始码代码才发现一个非常悲剧的问题。tomcat依然不支持热加载,这肯定是不行了,必须解决。因为ssm的各种依赖加起来几十个包,修改个东西跑起来既然要20多秒 。写代码的时间都没加载的时间长好吧?于是网上开始找,虽然东西多但是哥一个都没成功,有因为依赖的,有版本的,话说这个java都用上maven了为啥版本管理还是这么烂,不过也不能埋怨java,其实在版本管理上其他语言也都是一丘之貉!!于是乎发现了jetty这个货,正好没用过,对于我这样的尝鲜党必须试试,经过一番折腾终于搞定了,鉴于版本和jar包的版本问题,至少这个我的配置成功了!

 <build>
<plugins>
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.3.7.RC0</version>
<configuration>
<!--自动扫描文件改变并进行热部署的时间间隔,单位为秒。默认值为0,这代表着禁用扫描并热部署,只有一个大于0的配置可以使它生效。-->
<scanIntervalSeconds>10</scanIntervalSeconds>
<!--可选择的配置,如果没有设置,Jetty将创建ServerConnector实例来监听8080端口。-->
<httpConnector>
<!--port:连接监听的端口,默认8080;-->
<port>8080</port>
</httpConnector>
<webApp>
<!--你web应用的根路径(访问路径)。默认设置为“/”,如果你可以设置一个路径在“/”下面,例如/mycontext-->
<contextPath>/exam</contextPath>
</webApp>
<!-- scanTargetPatterns 可选。如果你想扫描有一长串的额外文件,通过使用模式匹配表达式制定它们更加方便,它可以用来替代 <scanTargets>参数的枚举展示。这个参数包含一组<scanTargetPattern>。每一个都是由一个<directory>和<includes>[或者<excludes>]参数来指定文件的匹配模式。-->
<scanTargetPatterns>
<scanTargetPattern>
<directory>src/main/webapp</directory>
<excludes>
<exclude>**/*.jsp</exclude>
</excludes>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
</scanTargetPattern>
</scanTargetPatterns>
<!-- 设置系统属性
你可以为插件的执行操作按name/value成对的方式指定系统属性。 在别的文件中 通过 ${configuration.path} 取值--> </configuration>
</plugin>

修改以后idea按ctrl+f9即可重新构建,终于不用重新启动容器了。然后开始增删查改起来!
  毕竟是java一定都不虚,这玩意依然是所有语言里最繁琐的。撸两个页面已经好半天了。如果可以尽量推荐你用python,或者note.js。不要浪费生命!在写表insert的时候有个createTime字段,基本上每个表都有着字段,一个一个赋值有觉得太麻烦,也是想到python里面有装饰器这样的工具可以搞定这样的需求,那java中注解和装饰器差不多会不会有相应的解决 方法呢!goole一圈果然有,就是定义注解方式,然后在mybatis里面增加一个拦截器,拦截到以后使用反射机制拿到被注解的字段设置属性。东西不多,但是是一个很好地解释注解使用方式以及反射的好例子。这里贴上来,以后可以回顾看看!

//定义注解  
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface CreateTime {
String value() default "";
} @Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface UpdateTime{
String value() default "";
}
//部分代码  在需要写入时间的字段上添加自己定义的注解

   private String email;
private String phoneNum;
@CreateTime //我是注解 对 我
private Date createTime;
private String createTimeStr;
private int createBy;
private int fieldId;
private String fieldName;
private Date lastLoginTime;
private String lastLoginTimeStr;
import org.aopalliance.intercept.Invocation;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import java.lang.reflect.Field;
import java.util.Date;
import java.util.Properties; // 这个必须把引入的包也展示出来 因为我刚开始就引包错了 如果用的同学尽量看仔细
//Object parameter = invocation.getArgs()[1]; 获取执行对象
// 通过反射获取对象所有的Field
// 遍历所有Field,查看是否有指定注解
// 如果有@CreateTime或者@UpdateTime注解,则设置最新时间 @Intercepts({ @Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }) })
public class CustomInterceptor implements Interceptor { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Override
public Object intercept(org.apache.ibatis.plugin.Invocation invocation) throws Throwable { MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0]; // 获取 SQL 命令
SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType(); // 获取参数
Object parameter = invocation.getArgs()[1]; // 获取私有成员变量
Field[] declaredFields = parameter.getClass().getDeclaredFields(); for (Field field : declaredFields) {
if (field.getAnnotation(CreateTime.class) != null) { //如果注解上CreateTime
if (SqlCommandType.INSERT.equals(sqlCommandType)) { // insert 语句插入 createTime
System.out.println("经过");
field.setAccessible(true);
field.set(parameter, new Date());
}
} if (field.getAnnotation(UpdateTime.class) != null) { // insert 或 update 语句插入 updateTime
if (SqlCommandType.INSERT.equals(sqlCommandType) || SqlCommandType.UPDATE.equals(sqlCommandType)) {
field.setAccessible(true);
field.set(parameter, new Date());
}
}
} return invocation.proceed();
} @Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
} @Override
public void setProperties(Properties properties) { }

测试就不贴了 !保准成功!

燃尽图

暑假撸系统3- petty热更新 mybatis自动填充时间字段!的更多相关文章

  1. mybatis自动填充时间字段

    对于实体中的created_on和updated_on来说,它没有必要被开发人员去干预,因为它已经足够说明使用场景了,即在插入数据和更新数据时,记录当前时间,这对于mybatis来说,通过拦截器是可以 ...

  2. mysql每次update数据,自动更新对应表中时间字段

    mysql 已经创建完成表的情况下, 使得其中的时间字段 在每次 uodate 数据的时候 自动更新事件, 运行如下sql ALTER TABLE tab_name MODIFY COLUMN upd ...

  3. 暑假撸系统1-先把git后悔药准备好!

    学校规定让暑假自己撸一款在线考试系统,其实的确需要一个款在线的考试系统系统,因为平时学校是使用Excel讲解选择题的.基于这个目标那么就话不多说.开干! 本来趁着项目想练练手,使用些新学习的技能看看, ...

  4. 暑假撸系统7- 熊孩子的捣乱!javascript保存前台状态!

    系统大体框架已经搭的差不多了, 往下就是技术性的美化以及修补了,但这也是最最耗费时间的.在这个过程就发现了一个有意思的需求,这里把思路以及解决方案总结下. 因为做的是考试系统,不管是大或者小的考试,本 ...

  5. 暑假撸系统5- Thymeleaf 常用标签的

    上次博客已经是三天前了,后期修补和细化的东西多了,进度没有前几天那么明显了.因为原来工作大多是后端居多,如果非要前台也会选择一些相对对ui依赖比较小的框架,比如extjs,所以这次的基础排版就费劲了, ...

  6. 暑假撸系统6- Thymeleaf ajax交互!

    本来用Thymeleaf也没想着深度使用ajax,就是用也是非常传统的ajax方式提交然后js控制修改下变量.闲来无事的时候看Thymeleaf的教程发现一哥们的实现方式,以及实现思路,堪称惊奇,先说 ...

  7. 关于webpack下热更新?&自动刷新?的小记(非vue-cli)

    写本随笔时:webpack4.6.0 为何标题用?号,因为老衲也不知是否用词正确,大概是这样的说法: webpack4.0引入生产模式和开发模式,在开发时使用 webpack 打包后不压缩,所以只需要 ...

  8. EF部分字段更新,自动忽略null字段

    某个项目里的update代码是类似这样的 public T Update<T>(T entity) where T : ModelBase { var set = this.Set< ...

  9. mybatis的判定时间字段问题 java.lang.IllegalArgumentException: invalid comparison: cn.hutool.core.date.DateTime and java.lang.String

    今天听组员说: mybatis在3.30版本及以上判定时间时 <if test="date_time != null and date_time != '' "> da ...

随机推荐

  1. Python之路 - Day4 - Python基础4 (新版)

    本节内容 迭代器&生成器 装饰器 Json & pickle 数据序列化 软件目录结构规范 作业:ATM项目开发 1.列表生成式,迭代器&生成器 列表生成式 孩子,我现在有个需 ...

  2. PAT 乙级 1002. 写出这个数 (20)(C语言描述)

    读入一个自然数n,计算其各位数字之和,用汉语拼音写出和的每一位数字. 输入格式:每个测试输入包含1个测试用例,即给出自然数n的值.这里保证n小于10100. 输出格式:在一行内输出n的各位数字之和的每 ...

  3. Vue3项目的简单搭建与项目结构的简单介绍

    Vue3项目的创建与运行 本文记录下自己近期学习的Vue3项目的创建,以及如何去运行一个Vue应用,同时包括对Vue项目结构进行一个简单的介绍. 一.node与npm的安装 通常平常进行开发的同学应该 ...

  4. 基于Jenkins+Maven+Gitea+Nexus从0到1搭建CICD环境

    在传统的单体软件架构中,软件开发.测试.运维都是以单个进程为单位. 当拆分成微服务之后,单个应用可以被拆分成多个微服务,比如用户系统,可以拆分成基本信息管理.积分管理.订单管理.用户信息管理.合同管理 ...

  5. 基于rabbitmq延迟插件实现分布式延迟任务

    承接上文基于redis,redisson的延迟队列实践,今天介绍下基于rabbitmq延迟插件rabbitmq_delayed_message_exchange实现延迟任务. 一.延迟任务的使用场景 ...

  6. 生产环境上,哨兵模式集群Redis版本升级应用实战

    背景: 由于生产环境上所使用的Redis版本并不一致,好久也没有更新,为了避免版本不同对Redis集群造成影响,从而升级为统一Redis版本! 1.集群架构 一主两从三哨兵: 2.升级方案 (1)升级 ...

  7. leetcode 28. 实现 strStr()

    问题描述 实现 strStr() 函数. 给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始).如果不 ...

  8. golang gin框架中实现"Transfer-Encoding: chunked"方式的分块发送数据到浏览器端

    参考了这篇帖子: https://golangtc.com/t/570b403eb09ecc66b90002d9 golang web如何发送小包的chunked数据 以下是代码: r.GET(&qu ...

  9. qt之线程

    第一种创建: mythread1.h: #ifndef MYTHREAD_H #define MYTHREAD_H #include<QThread> #include<QDebug ...

  10. java关键字final

    //继承弊端:打破了封装性 /* * final关键字: * 1,final是一个修饰符,可以修饰类,方法,变量. * 2,final修饰的类不可以被继承. * 3,final修饰的方法不可以被覆盖. ...