注解基本用法及简化XML配配置实例

前言:

注解作用:

注解,告诉编译器如何运行程序

注解和XML配置的区别:

传统方式通过配置文件告诉类如何运行,有了注解技术后,  
开发人员可以通过注解告诉类如何运行。  
在Java技术里注解的典型应用是:  
可以通过反射技术去得到类里面的注解,以决定怎么去运行类。

注解作用:

    1. 告诉编译器如何运行程序;
    2. 简化(取代)配置文件   

常用注解:

    // 重写父类的方法
1. @Override    
   // 抑制编译器警告
2. @SuppressWarnings({"unused","unchecked"})
   // 标记方法以及过时
3. @Deprecated

自定义注解格式:

public @interface Author {
    /**
     * 注解属性
     *    1. 修饰为默认或public
     *    2. 不能有主体
     */
    String name();
    int age() default 30;   // 带默认值的注解;  使用的时候就可以不写此属性值
}
public @interface Author {
    // 如果注解名称为value,使用时候可以省略名称,直接给值
    // (且注解只有一个属性时候才可以省略名称)
    String value();
}
使用
@Author("Jet")
@Author(value = "Jet")

注解属性类型为数组:

public @interface Author {

    String[] value() default {"test1","test2"};
}
使用:
@Author({“”,“”})
    public void save() {

    }

元注解

元注解,表示注解的注解!
指定注解的可用范围:

@Target({
TYPE,     类
FIELD,     字段
METHOD,  方法
PARAMETER,   参数
CONSTRUCTOR, 构造器
 LOCAL_VARIABLE  局部变量
})

元注解 - 2. 指定注解的声明周期

@Retention(RetentionPolicy.SOURCE)    注解只在源码级别有效
@Retention(RetentionPolicy.CLASS)      注解在字节码即别有效  默认值
@Retention(RetentionPolicy.RUNTIME)   注解在运行时期有效

前一章知道了泛型也可以使用反射:

父类通用类使用反射得到运行类的类型

但是有缺陷,因为 实体类名和数据库表名要一致,属性也要和字段一模一样才行。
可是事实上不是这样的:

当表名与数据库名称不一致、
 字段与属性不一样、
 主键不叫id

解决方案1:

    可以通过配置文件(XML) 解决!
    类似于:配置类名=表名 属性名=字段名

解决方案2:

    使用注解! 
    1. 自定义注解 使得属性对应列名,还有类名对应表名
    2. 再设置个无属性的注解,标识主键对应的属性
    3. 使用元注解设置生命周期为运行环境
    4. 使用元注解设置注解范围

先看看两者区别:
注解:

    简化XML配置, 程序处理非常方便!
    (不便于维护: 例如修改字段名,要重新编译!)

XML

    便于维护!  需要些读取代码!

两者区别:

传统方式通过配置文件告诉类如何运行,有了注解技术后,  
开发人员可以通过注解告诉类如何运行。  
在Java技术里注解的典型应用是:    
可以通过反射技术去得到类里面的注解,以决定怎么去运行类。

接下来看看优化之前的BasicDao通用类:
JdbcUtilsC3p0就不多介绍了

实体类:


@Table(tableName = "students")
public class Students {

    @id
    @Column(columnName = "id")
    private int student_id;

    @Column(columnName = "name")
    private String student_name;

    @Column(columnName = "age")
    private int student_age;


    @Override
    public String toString() {
        // TODO Auto-generated method stub
        return student_id + ":" + student_name + ":" + student_age;
    }
}

自定义注解:
1. Table注解:

import static java.lang.annotation.ElementType.TYPE;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
    String tableName();
}

id注解:

import static java.lang.annotation.ElementType.FIELD;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface id {

}

Column注解:

import static java.lang.annotation.ElementType.FIELD;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
    String columnName();
}

子类:

public class StudentDao extends BasicDao<Students>{

}

通用父类:

public class BasicDao<T> {
    private Class<T> clazz;
    private String tableName;
    private String id_primary;

    public BasicDao() {

        Type type = this.getClass().getGenericSuperclass(); // BasicDao<Students>
        // 强转参数化类型
        ParameterizedType pType = (ParameterizedType) type;

        Type[] types = pType.getActualTypeArguments();
        // 获得参数化类型的实参:Students
        clazz = (Class<T>) types[0];
        // 获得注解
        Table table = clazz.getAnnotation(Table.class);
        // 得到该对象对应的数据库表名称
        tableName = table.tableName();
        // 获得该类的属性数组
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            // 可以强制访问class的private类型的属性
            field.setAccessible(true);
            id id_a = field.getAnnotation(id.class);

            if (id_a != null) {
                Column column = field.getAnnotation(Column.class);
                id_primary = column.columnName();
                break;
            }
        }
        System.out.println("表名:" + tableName);
        System.out.println("主键:" + id_primary);
    }

    public T findById(int i) {
        String sql = "SELECT *FROM " + tableName + " WHERE " + id_primary + "=?";
        try {
            return JdbcUtilsC3p0.getQueryRunner().query(sql, new MyBeanHandler<T>(clazz), i);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            throw new RuntimeException(e);
        }
    }
    public List<T> finAll() {
        String sql = "SELECT *FROM " + tableName ;
        try {
            return JdbcUtilsC3p0.getQueryRunner().query(sql, new MyBeanListHandler<T>(clazz));
        } catch (Exception e) {
            // TODO Auto-generated catch block
            throw new RuntimeException(e);
        }
    }
}

class MyBeanHandler<T> implements ResultSetHandler<T> {

    private Class<T> clazz;

    public MyBeanHandler(Class<T> clazz) {
        this.clazz = clazz;
    }

    @Override
    public T handle(ResultSet arg0) throws SQLException {
        try {
            T c = clazz.newInstance();
            if (arg0.next()) {
                // 获取类的所有的Field字段数组
                Field[] fields = clazz.getDeclaredFields();
                // 其中还有个$jacocoData
                System.out.println(fields.length);
                for (Field field : fields) {
                    if (!"$jacocoData".equals(field.getName())) {
                        // 获取属性名
                        String fieldName = field.getName();
                        // 获得属性上的注解
                        Column column = field.getAnnotation(Column.class);
                        // 获得属性对应的数据库表的字段
                        String name = column.columnName();
                        // 得到字段值
                        Object value = arg0.getObject(name);
                        BeanUtils.copyProperty(c, fieldName, value);
                    }
                }
            }
            return c;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

class MyBeanListHandler<T> implements ResultSetHandler<List<T>>{
    private Class<T> clazz;

    public MyBeanListHandler(Class<T> clazz) {
        this.clazz = clazz;
    }
    @Override
    public List<T> handle(ResultSet arg0) throws SQLException {
        try {
            List<T> list = new ArrayList<T>();
            while(arg0.next()) {
                T c = clazz.newInstance();
                // 获取类的所有的Field字段数组
                Field[] fields = clazz.getDeclaredFields();
                // 其中还有个$jacocoData
                System.out.println(fields.length);
                for (Field field : fields) {
                    if (!"$jacocoData".equals(field.getName())) {
                        // 获取属性名
                        String fieldName = field.getName();
                        // 获得属性上的注解
                        Column column = field.getAnnotation(Column.class);
                        // 获得属性对应的数据库表的字段
                        String name = column.columnName();
                        // 得到字段值
                        Object value = arg0.getObject(name);
                        BeanUtils.copyProperty(c, fieldName, value);
                    }
                }
                list.add(c);
            }
            return list;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}

主程序入口:

public static void main(String[] args) throws  Exception {
        StudentDao studentDao = new StudentDao();
        Students students = studentDao.findById(1);
        System.out.println(students);
        System.out.println("__________________________________________");
        List<Students> list = new ArrayList<Students>();
        list= studentDao.finAll();
        for(Students s:list) {
            System.out.println(s);
        }
    }

输出:

表名:students
主键:id
808, 2018 9:46:34 下午 com.mchange.v2.log.MLog 
信息: MLog clients using java 1.4+ standard logging.
808, 2018 9:46:34 下午 com.mchange.v2.c3p0.C3P0Registry 
信息: Initializing c3p0-0.9.5.2 [built 08-December-2015 22:06:04 -0800; debug? true; trace: 10]
808, 2018 9:46:35 下午 com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource 
信息: Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, contextClassLoaderSource -> caller, dataSourceName -> 1hge4n59x75lm5msdkh6h|44c73c26, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.cj.jdbc.Driver, extensions -> {}, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, forceSynchronousCheckins -> false, forceUseNamedDriverClass -> false, identityToken -> 1hge4n59x75lm5msdkh6h|44c73c26, idleConnectionTestPeriod -> 0, initialPoolSize -> 3, jdbcUrl -> jdbc:mysql://localhost:3306/daynow?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&useSSL=false, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 1000, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 6, maxStatements -> 0, maxStatementsPerConnection -> 0, minPoolSize -> 3, numHelperThreads -> 3, preferredTestQuery -> null, privilegeSpawnedThreads -> false, properties -> {password=******, user=******}, propertyCycle -> 0, statementCacheNumDeferredCloseThreads -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, userOverrides -> {}, usesTraditionalReflectiveProxies -> false ]
4
1:我:12
__________________________________________
4
4
1:我:12
2:你:33
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值