|
| 1 | +--- |
| 2 | +layout: post |
| 3 | +categories: [Java] |
| 4 | +description: none |
| 5 | +keywords: Java |
| 6 | +--- |
| 7 | +# Java注解 |
| 8 | + |
| 9 | +## 什么是注解? |
| 10 | +注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。 |
| 11 | + |
| 12 | +相信很多学过spring等框架的同学对注解一定不陌生吧!比如@Service,@Repository,@Autowired等等。就算没有学过框架,但凡你只要学了java基础,你都会接触到注解。比如一个子类继承父类的方法,该方法前面会有@Override,这个其实就是注解! |
| 13 | + |
| 14 | +## 如何声明注解? |
| 15 | +使用@interface关键字就能声明一个注解。如下例: |
| 16 | +``` |
| 17 | +public @interface TestAnno { |
| 18 | +
|
| 19 | +} |
| 20 | +``` |
| 21 | + |
| 22 | +## 如何声明注解的生命周期和作用域? |
| 23 | +``` |
| 24 | +@Target(ElementType.FIELD) //作用域 FIELD表示只能作用在字段中 |
| 25 | +@Retention(RetentionPolicy.RUNTIME) //生命周期 RUNTIME表示运行时有效 |
| 26 | +@Documented //让它定制文档化功能,使用使用此注解时必须设置RetentionPolicy为RUNTIME |
| 27 | +@Inherited //让它允许继承,可作用到子类 |
| 28 | +public @interface Column { |
| 29 | + /** |
| 30 | + * 属性变量只能声明无参无异常的,当只有一个属性时,属性名称为value, |
| 31 | + */ |
| 32 | + String value(); |
| 33 | +} |
| 34 | +``` |
| 35 | +ElementType中的所有值都可以作为@Column的作用域,而且作用域可以同时有多个值比如@Target(ElementType.TYPE,ElementType.FIELD)表示该注解可以作用在类上,也能作用在字段上。 |
| 36 | + |
| 37 | +RetentionPolicy的取值有三个,分别是SOURCE,CLASS,RUNTIME。分别表示源码注解,注解会保留在源码中,在编译和运行时无效。编译注解,注解会保留在class文件中,编译时会识别,运行时不识别。运行时注解,注解会保留到class文件中,同时运行时也会被识别。 |
| 38 | + |
| 39 | +## 注解的应用 |
| 40 | +注解的应用十分广泛,这里只展示一小个方面来说明注解的使用原理。当我们使用数据库查询数据时,大多数时候需要我们自己来写sql语句,当我们的逻辑比较多,较复杂时,会显得非常不方便。下面将使用自定义注解实现自动拼接sql,然后自动封装查询结果 |
| 41 | + |
| 42 | +首先自定义两个注解 |
| 43 | +```java |
| 44 | +@Target(ElementType.FIELD) //作用域 FIELD表示只能作用在字段中 |
| 45 | +@Retention(RetentionPolicy.RUNTIME) //生命周期 RUNTIME表示运行时有效 |
| 46 | +public @interface Column { |
| 47 | + /** |
| 48 | + * 属性变量只能声明无参无异常的,当只有一个属性时,属性名称为value |
| 49 | + */ |
| 50 | + String value(); |
| 51 | +} |
| 52 | +``` |
| 53 | + |
| 54 | +```java |
| 55 | +@Target(ElementType.TYPE) //作用域 TYPE表示只能作用在类中 |
| 56 | +@Retention(RetentionPolicy.RUNTIME)//生命周期 RUNTIME表示运行时有效 |
| 57 | +public @interface Table { |
| 58 | + /** |
| 59 | + * 属性变量只能是无参无异常的,当只有一个属性时,属性名称为value |
| 60 | + */ |
| 61 | + String value(); |
| 62 | +} |
| 63 | +``` |
| 64 | + |
| 65 | +创建一个javaBean |
| 66 | +``` |
| 67 | +@Table("USER") |
| 68 | +public class User implements java.io.Serializable { |
| 69 | + |
| 70 | + private static final long serialVersionUID = 1L; |
| 71 | + |
| 72 | + private int id; |
| 73 | + |
| 74 | + @Column("USER_ID") |
| 75 | + private String userId; //用户ID |
| 76 | + |
| 77 | + @Column("USER_NAME") |
| 78 | + private String userName; //用户名称 |
| 79 | + |
| 80 | + @Column("PASSWORD") |
| 81 | + private String password; //用户密码 |
| 82 | + |
| 83 | + @Column("SEX") |
| 84 | + private String sex; //用户性别 |
| 85 | + |
| 86 | + @Column("EMAIL") |
| 87 | + private String email; //电子邮件 |
| 88 | + |
| 89 | + @Column("PHONE") |
| 90 | + private String phone; //联系电话 |
| 91 | + |
| 92 | + @Column("BIRTHDAY") |
| 93 | + private Date birthday; //出生日期 |
| 94 | + |
| 95 | + @Column("ADDRESS") |
| 96 | + private String address; //家庭住址 |
| 97 | + |
| 98 | + @Column("ACTIVE_FLAG") |
| 99 | + private int activeFlag=1; //用户活跃标志:0 删除,1 活跃 |
| 100 | + |
| 101 | + |
| 102 | + public String getUserId() { |
| 103 | + return userId; |
| 104 | + } |
| 105 | + public void setUserId(String userId) { |
| 106 | + this.userId = userId; |
| 107 | + } |
| 108 | + public String getUserName() { |
| 109 | + return userName; |
| 110 | + } |
| 111 | + public void setUserName(String userName) { |
| 112 | + this.userName = userName; |
| 113 | + } |
| 114 | + public String getPassword() { |
| 115 | + return password; |
| 116 | + } |
| 117 | + public void setPassword(String password) { |
| 118 | + this.password = password; |
| 119 | + } |
| 120 | + public String getSex() { |
| 121 | + return sex; |
| 122 | + } |
| 123 | + public void setSex(String sex) { |
| 124 | + this.sex = sex; |
| 125 | + } |
| 126 | + public String getEmail() { |
| 127 | + return email; |
| 128 | + } |
| 129 | + public void setEmail(String email) { |
| 130 | + this.email = email; |
| 131 | + } |
| 132 | + public String getPhone() { |
| 133 | + return phone; |
| 134 | + } |
| 135 | + public void setPhone(String phone) { |
| 136 | + this.phone = phone; |
| 137 | + } |
| 138 | + public Date getBirthday() { |
| 139 | + return birthday; |
| 140 | + } |
| 141 | + public void setBirthday(Date birthday) { |
| 142 | + this.birthday = birthday; |
| 143 | + } |
| 144 | + public String getAddress() { |
| 145 | + return address; |
| 146 | + } |
| 147 | + public void setAddress(String address) { |
| 148 | + this.address = address; |
| 149 | + } |
| 150 | + public int getActiveFlag() { |
| 151 | + return activeFlag; |
| 152 | + } |
| 153 | + public void setActiveFlag(int activeFlag) { |
| 154 | + this.activeFlag = activeFlag; |
| 155 | + } |
| 156 | + public int getId() { |
| 157 | + return id; |
| 158 | + } |
| 159 | + public void setId(int id) { |
| 160 | + this.id = id; |
| 161 | + } |
| 162 | + |
| 163 | +} |
| 164 | +``` |
| 165 | + |
| 166 | +创建一个JdbcUtil的工具类,使用的是c3p0连接池 |
| 167 | +``` |
| 168 | +public class JdbcUtil { |
| 169 | + |
| 170 | + private static ComboPooledDataSource dataSource = new ComboPooledDataSource(); |
| 171 | + |
| 172 | + private static Connection getConnection() { |
| 173 | + Connection connection = null; |
| 174 | + try { |
| 175 | + connection = dataSource.getConnection(); |
| 176 | + } catch (SQLException e) { |
| 177 | + e.printStackTrace(); |
| 178 | + } |
| 179 | + return connection; |
| 180 | + } |
| 181 | + @SuppressWarnings({ "unchecked", "rawtypes" }) |
| 182 | + public static List<Object> query(Object o) { |
| 183 | + Class c = o.getClass();//获取类对象 |
| 184 | + StringBuffer sb = new StringBuffer(); |
| 185 | + boolean isExist = c.isAnnotationPresent(Table.class);//判断c中是否存在注解 |
| 186 | + String tableName = null; |
| 187 | + if (isExist) { |
| 188 | + //获取表名 |
| 189 | + Table table = (Table)c.getAnnotation(Table.class); |
| 190 | + tableName = table.value(); |
| 191 | + sb.append("select * from ").append(tableName).append(" where 1=1"); |
| 192 | + } |
| 193 | + Field[] fields = c.getDeclaredFields(); |
| 194 | + //遍历字段名 |
| 195 | + for (Field field:fields) { |
| 196 | + //判断该字段是否存在注解 |
| 197 | + if (field.isAnnotationPresent(Column.class)) { |
| 198 | + //获取字段名 |
| 199 | + Column column = field.getAnnotation(Column.class); |
| 200 | + String columnName = column.value(); |
| 201 | + //获取字段值 |
| 202 | + String fieldName = field.getName(); |
| 203 | + String getMethodName = "get"+fieldName.substring(0, 1).toUpperCase()+fieldName.substring(1); |
| 204 | + Object fieldValue = null; |
| 205 | + try { |
| 206 | + fieldValue = c.getMethod(getMethodName).invoke(o); |
| 207 | + } catch (Exception e) { |
| 208 | + e.printStackTrace(); |
| 209 | + } |
| 210 | + //拼接sql |
| 211 | + if (fieldValue!=null) { |
| 212 | + sb.append(" and ").append(columnName).append("="); |
| 213 | + if (fieldValue instanceof String) { |
| 214 | + sb.append("'").append(fieldValue).append("'"); |
| 215 | + }else if (fieldValue instanceof Integer) { |
| 216 | + sb.append(fieldValue); |
| 217 | + } |
| 218 | + } |
| 219 | + } |
| 220 | + } |
| 221 | + String sql = sb.toString(); |
| 222 | + Connection connection = null; |
| 223 | + PreparedStatement preparedStatement = null; |
| 224 | + ResultSet rs = null; |
| 225 | + try { |
| 226 | + connection = getConnection(); |
| 227 | + preparedStatement = connection.prepareStatement(sql); |
| 228 | + rs = preparedStatement.executeQuery(); |
| 229 | + ResultSetMetaData rMetaData = rs.getMetaData();//获取元数据对象 |
| 230 | + List<Object> list = new ArrayList<Object>(); |
| 231 | + while (rs.next()) { |
| 232 | + Object object = c.newInstance();//通过类对象获取实例对象 |
| 233 | + for (int i = 1; i <= rMetaData.getColumnCount(); i++) { |
| 234 | + Object value = rs.getObject(i);//获取该列的值 |
| 235 | + for (int j = 0; j < fields.length; j++) { |
| 236 | + if (fields[j].getName().equalsIgnoreCase(rMetaData.getColumnName(i).replace("_", ""))) { |
| 237 | + fields[j].setAccessible(true);//私有变量,其它对象不具有访问权,故设置可访问标志为true,给fields[j]提供权限 |
| 238 | + fields[j].set(object, value); |
| 239 | + fields[j].setAccessible(fields[j].isAccessible());//还原可访问标志 |
| 240 | + } |
| 241 | + } |
| 242 | + } |
| 243 | + list.add(object); |
| 244 | + } |
| 245 | + return list; |
| 246 | + } catch (Exception e) { |
| 247 | + e.printStackTrace(); |
| 248 | + }finally { |
| 249 | + close(connection, preparedStatement, rs); |
| 250 | + } |
| 251 | + return null; |
| 252 | + } |
| 253 | + |
| 254 | + private static void close(Connection connection,PreparedStatement preparedStatement,ResultSet resultSet) { |
| 255 | + try { |
| 256 | + if (connection!=null) { |
| 257 | + connection.close(); |
| 258 | + } |
| 259 | + if (preparedStatement!=null) { |
| 260 | + preparedStatement.close(); |
| 261 | + } |
| 262 | + if (resultSet!=null) { |
| 263 | + resultSet.close(); |
| 264 | + |
| 265 | + } |
| 266 | + } catch (Exception e) { |
| 267 | + e.printStackTrace(); |
| 268 | + } |
| 269 | + } |
| 270 | +} |
| 271 | +``` |
| 272 | +在该工具类中,query(Object o)方法就是通过反射的方式来解析注解,获取注解中的值,然后进行相应的处理 |
| 273 | + |
| 274 | +写个测试类来验证一下 |
| 275 | +```java |
| 276 | +public class Test { |
| 277 | + @org.junit.Test |
| 278 | + public void test1() { |
| 279 | + User user = new User(); |
| 280 | + user.setUserName("tom352"); |
| 281 | + List<Object> list = JdbcUtil.query(user); |
| 282 | + List<User> userList = new ArrayList<User>(); |
| 283 | + if (list!=null && list.size()>0) { |
| 284 | + for (Object object : list) { |
| 285 | + userList.add((User)object); |
| 286 | + } |
| 287 | + } |
| 288 | + if (userList!=null && userList.size()>0) { |
| 289 | + System.out.println(userList.get(0)); |
| 290 | + } |
| 291 | + } |
| 292 | +} |
| 293 | +``` |
| 294 | + |
| 295 | + |
| 296 | + |
| 297 | + |
| 298 | + |
| 299 | + |
| 300 | + |
| 301 | + |
| 302 | + |
| 303 | + |
| 304 | + |
| 305 | + |
| 306 | + |
| 307 | + |
| 308 | + |
0 commit comments