暑假撸系统3- petty热更新 mybatis自动填充时间字段!
经过了昨天纠结技术选型,和一大堆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自动填充时间字段!的更多相关文章
- mybatis自动填充时间字段
对于实体中的created_on和updated_on来说,它没有必要被开发人员去干预,因为它已经足够说明使用场景了,即在插入数据和更新数据时,记录当前时间,这对于mybatis来说,通过拦截器是可以 ...
- mysql每次update数据,自动更新对应表中时间字段
mysql 已经创建完成表的情况下, 使得其中的时间字段 在每次 uodate 数据的时候 自动更新事件, 运行如下sql ALTER TABLE tab_name MODIFY COLUMN upd ...
- 暑假撸系统1-先把git后悔药准备好!
学校规定让暑假自己撸一款在线考试系统,其实的确需要一个款在线的考试系统系统,因为平时学校是使用Excel讲解选择题的.基于这个目标那么就话不多说.开干! 本来趁着项目想练练手,使用些新学习的技能看看, ...
- 暑假撸系统7- 熊孩子的捣乱!javascript保存前台状态!
系统大体框架已经搭的差不多了, 往下就是技术性的美化以及修补了,但这也是最最耗费时间的.在这个过程就发现了一个有意思的需求,这里把思路以及解决方案总结下. 因为做的是考试系统,不管是大或者小的考试,本 ...
- 暑假撸系统5- Thymeleaf 常用标签的
上次博客已经是三天前了,后期修补和细化的东西多了,进度没有前几天那么明显了.因为原来工作大多是后端居多,如果非要前台也会选择一些相对对ui依赖比较小的框架,比如extjs,所以这次的基础排版就费劲了, ...
- 暑假撸系统6- Thymeleaf ajax交互!
本来用Thymeleaf也没想着深度使用ajax,就是用也是非常传统的ajax方式提交然后js控制修改下变量.闲来无事的时候看Thymeleaf的教程发现一哥们的实现方式,以及实现思路,堪称惊奇,先说 ...
- 关于webpack下热更新?&自动刷新?的小记(非vue-cli)
写本随笔时:webpack4.6.0 为何标题用?号,因为老衲也不知是否用词正确,大概是这样的说法: webpack4.0引入生产模式和开发模式,在开发时使用 webpack 打包后不压缩,所以只需要 ...
- EF部分字段更新,自动忽略null字段
某个项目里的update代码是类似这样的 public T Update<T>(T entity) where T : ModelBase { var set = this.Set< ...
- 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 ...
随机推荐
- Word2010制作自动目录
原文链接:https://www.toutiao.com/i6488296610873737741/ 原文从网上复制: 查看"开始"选项卡,"样式"功能组,我们 ...
- element ui 动态菜单解决方案集锦
1.<分享一个VUE Element-UI 的多级菜单动态渲染的组件> 2.<饿了么组件库,element-ui开发精美的后台管理系统系列之(一)开发伸缩菜单> 3.<V ...
- Keil MDK STM32系列(六) 基于抽象外设库HAL的ADC模数转换
Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...
- Kotlin 协程一 —— 全面了解 Kotlin 协程
一.协程的一些前置知识 1.1 进程和线程 1.1.1基本定义 1.1.2为什么要有线程 1.1.3 进程与线程的区别 1.2 协作式与抢占式 1.2.1 协作式 1.2.2 抢占式 1.3 协程 二 ...
- 2月10日 体温APP开发总结
1.Java代码 1.user package bean;public class User { private String name; private String riqi; private S ...
- gin中的多模板和模板继承的用法
1. 简单用法 package main import ( "github.com/gin-contrib/multitemplate" "github.com/gin- ...
- gin使用BasicAuth中间件
package mainimport ( "github.com/gin-gonic/gin" "net/http")// 模拟一些私人数据var secret ...
- IoC容器-Bean管理注解方式(完全注解开发)
完全注解开发 (1)创建配置类,替代xml配置文件 (2)编写测试类 在实际中一般用springboot做
- 带你十天轻松搞定 Go 微服务系列(三)
序言 我们通过一个系列文章跟大家详细展示一个 go-zero 微服务示例,整个系列分十篇文章,目录结构如下: 环境搭建 服务拆分 用户服务(本文) 产品服务 订单服务 支付服务 RPC 服务 Auth ...
- Java安全之C3P0利用与分析
Java安全之C3P0利用与分析 目录 Java安全之C3P0利用与分析 写在前面 C3P0 Gadget http base C3P0.getObject() 序列化 反序列化 Class.forN ...