缘起:好久没写博客了,最近工作写了一些,服务的接口,自己写白盒测试进行测试,全部通过,
但是部署到线上会导致一些服务调不通追下问题,发现是自己粗心忘记加了一些注解,
最后把注解加上了,BUG消除,仔细思考一下,自己对注解知知甚少。
Java注解:
1、@Target
2、@Retention
3、@Documented
4、@Inherited 5、自定义注解
每个注解对应含义再次做过多描述,只简单的列举1、2、对应的含义:
@Target:
作用:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)
取值(ElementType)有:
1、CONSTRUCTOR:用于描述构造器
2、FIELD
:
用于描述域
3、LOCAL_VARIABLE
:
用于描述局部变量
4、METHOD
:
用于描述方法
5、PACKAGE
:
用于描述包
6、PARAMETER
:
用于描述参数
7、TYPE
:
用于描述类、接口(包括注解类型) 或enum声明
@Retention:
作用:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)
取值(RetentionPoicy)有:
1、SOURCE
:
在源文件中有效(即源文件保留)
2、CLASS
:
在class文件中有效(即class保留)
3、RUNTIME
:
在运行时有效(即运行时保留)
自己简单的看过类似相关注解,再结合一些demo自己模仿的写了一点,sql语句的自动生成小工具Util代码,
先展示一下测试代码:
public class test { public static void main(String[] args){ System.out.println(SqlUtil.create(Person.class)); System.out.println(SqlUtil.insert(Person.class)); } }
CREATE TABLE person(name String not null,id int primary key auto_increment) INSERT INTO person (name,id) VALUES(?,?)
只有简单的几行代码,会对应生成指定类的create table,inset 语句,
用法只需要对应新建Person类的时候加入指定注解即可
Person类如下所示:
@Table(name="person") public class Person { @PrimaryKey(name="id") public int id; @Column(name="name",isNull = false) public String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
下面为@Table注解实现,主要用来获取对应table 名称
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Table { public String name() default ""; }
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Column { public String name() default ""; public int length() default 255; public boolean isNull() default true; }
下面就是重头戏啦 SqlUtil工具类
package com.ucky.annotation.hibernate; import java.lang.reflect.Field; import java.util.Date; import java.util.HashMap; import java.util.Map; /** * 生成建表语句 */ public class SqlUtil { /* * 生成创建table语句 * */ public static String create(Class<?> clazz) { StringBuilder sb = new StringBuilder(); String tableName = getTableName(clazz); if (null == tableName || "".equals(tableName)) { return null; } sb.append("CREATE TABLE ").append(tableName).append("("); Map<String, String> columnMap = getColumn(clazz); for (Map.Entry<String, String> entry : columnMap.entrySet()) { sb.append(entry.getKey()); sb.append(" "); sb.append(entry.getValue()); sb.append(","); } sb.deleteCharAt(sb.length() - 1); sb.append(")"); return sb.toString(); } /* * 生成插入语句 * */ public static String insert(Class<?> clazz) { StringBuilder sb = new StringBuilder(); String tableName = getTableName(clazz); sb.append("INSERT INTO ").append(tableName).append(" ("); Map<String, String> columnMap = getColumn(clazz); for (Map.Entry<String, String> entry : columnMap.entrySet()) { sb.append(entry.getKey()); sb.append(","); } sb.deleteCharAt(sb.length() - 1); sb.append(") ").append("VALUES").append("("); for (int i = 0; i < columnMap.size(); i++) { sb.append("?").append(","); } sb.deleteCharAt(sb.length() - 1); sb.append(")"); return sb.toString(); } public static String delete() { return null; } /* * 获取表名称 * */ public static String getTableName(Class<?> clazz) { //判断是否为Table注释类型是方法返回true,否则返回false if (clazz.isAnnotationPresent(Table.class)) { //获取注解信息 Table table = clazz.getAnnotation(Table.class); if(!"".equals(table.name())){ return table.name(); } } return null; } /* * 获取字段信息的Map * */ public static Map<String, String> getColumn(Class<?> clazz) { Map<String, String> columns = new HashMap<String, String>(); //通过反射取得所有Field,因为table那里是注解指定的注解,类型,column是对应方法上的所以不能class.isAnnotationPresent直接判断 Field[] fields = clazz.getDeclaredFields(); if (fields != null) { String columnName, type; Column column; for (int i$ = 0; i$ < fields.length; i$++) { //判断当前field是否为Column注解 if (fields[i$].isAnnotationPresent(Column.class)) { //获取注解对象 column = fields[i$].getAnnotation(Column.class); columnName = column.name(); if("".equals(columnName)){ throw new RuntimeException("未找到对应字段名:" + i$); } //根据不同类型生成不同的SQL if (int.class.isAssignableFrom(fields[i$].getType())) { type = "int"; } else if (String.class.isAssignableFrom(fields[i$].getType())) { type = "String"; } else if (Date.class.isAssignableFrom(fields[i$].getType())) { type = "Date"; } else { throw new RuntimeException("不支持数据类型:" + fields[i$].getType().getSimpleName()); } type += (column.isNull() ? " " : " NOT NULL"); columns.put(columnName, type); } else if (fields[i$].isAnnotationPresent(PrimaryKey.class)) { PrimaryKey primaryKey = fields[i$].getAnnotation(PrimaryKey.class); //将一个类的成员变量置为private,其实我也不知道啥意思,有知道的指点一下 ,谢谢! fields[i$].setAccessible(true); columnName = primaryKey.name(); if("".equals(columnName)){ throw new RuntimeException("未找到对应主键名" ); } type = "INT PRIMARY KEY AUTO_INCREMENT"; columns.put(columnName, type); } } } return columns; } }
其实对于结果,表现的还不够理想,理想方法是把值,对应的Person对象也传入,返回sql语句插入带有具体的值,(一会写,来个BUG。。。。)