暑假撸系统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) { }
测试就不贴了 !保准成功!
燃尽图