1.spring注解:主要是为了声明spring相关的各种组件,提供了一种非xml的配置方式,使用注解方式可以大大减少配置文件,节约项目空间,但是因为使用硬编码,不方便阅读且不入xml配置方式易拓展。
使用方式:网上很多例子不再赘诉.
2.java注解:从名字上看是注释,解释。但功能却不仅仅是注释那么简单。注解(Annotation) 为我们在代码中添加信息提供了一种形式化的方法,是我们可以在稍后 某个时刻方便地使用这些数据(通过 解析注解 来使用这些数据),常见的作用有以下几种:
- 生成文档。这是最常见的,也是java 最早提供的注解。常用的有@see @param @return 等
- 跟踪代码依赖性,实现替代配置文件功能。比较常见的是spring 2.5 开始的基于注解配置。作用就是减少配置。现在的框架基本都使用了这种配置来减少配置文件的数量。也是
- 在编译时进行格式检查。如@Override 放在方法前,如果你这个方法并不是覆盖了超类方法,则编译时就能检查出。
要点:
(1). 要用好注解,必须熟悉java 的反射机制,注解的解析完全依赖于反射。
(2). 不要滥用注解。平常我们编程过程很少接触和使用注解,只有做设计,且不想让设计有过多的配置时。
自定义注解相关知识:
java.lang.annotation 中包含所有定义自定义注解所需用到的原注解和接口。如接口 java.lang.annotation.Annotation 是所有注解继承的接口,并且是自动继承,不需要定义时指定,类似于所有类都自动继承Object。
该包同时定义了四个元注解,Documented,Inherited,Target(作用范围,方法,属性,构造方法等),Retention(生命范围,源代码,class,runtime)。下面将在实例中逐个讲解他们的作用,及使用方法。
Inherited : 在您定义注解后并使用于程序代码上时,预设上父类别中的注解并不会被继承至子类别中,您可以在定义注解时加上java.lang.annotation.Inherited 限定的Annotation,这让您定义的Annotation型别被继承下来。注意注解继承只针对class 级别注解有效(这段建议看完全文后在来回顾)
四个元注解分别是:@Target,@Retention,@Documented,@Inherited ,再次强调下元注解是java API提供,是专门用来定义注解的注解,其作用分别如下。
@Target 表示该注解用于什么地方,可能的值在枚举类 ElemenetType 中,包括:
ElemenetType.CONSTRUCTOR 构造器声明
ElemenetType.FIELD 域声明(包括 enum 实例)
ElemenetType.LOCAL_VARIABLE 局部变量声明
ElemenetType.METHOD 方法声明
ElemenetType.PACKAGE 包声明
ElemenetType.PARAMETER 参数声明
ElemenetType.TYPE 类,接口(包括注解类型)或enum声明
@Retention 表示在什么级别保存该注解信息。可选的参数值在枚举类型 RetentionPolicy 中,包括:
RetentionPolicy.SOURCE 注解将被编译器丢弃
RetentionPolicy.CLASS 注解在class文件中可用,但会被VM丢弃
RetentionPolicy.RUNTIME VM将在运行期也保留注释,因此可以通过反射机制读取注解的信息。
@Documented 将此注解包含在 javadoc 中 ,它代表着此注解会被javadoc工具提取成文档。在doc文档中的内容会因为此注解的信息内容不同而不同。相当与@see,@param 等。
@Inherited 允许子类继承父类中的注解。
@interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。可以通过default来声明参数的默认值。
下面到了最重要的一步了,就是如何读取我们在类中定义的注解。只要读取出来了使用的话就简单了。
jdk1.5 既然增加了注解,肯定就增加了相关读取的api
在java.lang.reflect包中新增了AnnotatedElement接口,JDK源码如下:
public interface AnnotatedElement { boolean isAnnotationPresent(Class<? extends Annotation> annotationClass); <T extends Annotation> T getAnnotation(Class<T> annotationClass); Annotation[] getAnnotations(); Annotation[] getDeclaredAnnotations(); }
- isAnnotationPresent:判断是否标注了指定注解
- getAnnotation:获取指定注解,没有则返回null
- getAnnotations:获取所有注解,包括继承自基类的,没有则返回长度为0的数组
- getDeclaredAnnotations:获取自身显式标明的所有注解,没有则返回长度为0的数组
package com.tmser.annotation; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Method; public class ParseAnnotation { /** * 简单打印出UserAnnotation 类中所使用到的类注解 * 该方法只打印了 Type 类型的注解 * @throws ClassNotFoundException */ public static void parseTypeAnnotation() throws ClassNotFoundException { Class clazz = Class.forName("com.tmser.annotation.UserAnnotation"); Annotation[] annotations = clazz.getAnnotations(); for (Annotation annotation : annotations) { TestA testA = (TestA)annotation; System.out.println("id= \""+testA.id()+"\"; name= \""+testA.name()+"\"; gid = "+testA.gid()); } } /** * 简单打印出UserAnnotation 类中所使用到的方法注解 * 该方法只打印了 Method 类型的注解 * @throws ClassNotFoundException */ public static void parseMethodAnnotation(){ Method[] methods = UserAnnotation.class.getDeclaredMethods(); for (Method method : methods) { /* * 判断方法中是否有指定注解类型的注解 */ boolean hasAnnotation = method.isAnnotationPresent(TestA.class); if (hasAnnotation) { /* * 根据注解类型返回方法的指定类型注解 */ TestA annotation = method.getAnnotation(TestA.class); System.out.println("method = " + method.getName() + " ; id = " + annotation.id() + " ; description = " + annotation.name() + "; gid= "+annotation.gid()); } } } /** * 简单打印出UserAnnotation 类中所使用到的方法注解 * 该方法只打印了 Method 类型的注解 * @throws ClassNotFoundException */ public static void parseConstructAnnotation(){ Constructor[] constructors = UserAnnotation.class.getConstructors(); for (Constructor constructor : constructors) { /* * 判断构造方法中是否有指定注解类型的注解 */ boolean hasAnnotation = constructor.isAnnotationPresent(TestA.class); if (hasAnnotation) { /* * 根据注解类型返回方法的指定类型注解 */ TestA annotation =(TestA) constructor.getAnnotation(TestA.class); System.out.println("constructor = " + constructor.getName() + " ; id = " + annotation.id() + " ; description = " + annotation.name() + "; gid= "+annotation.gid()); } } } public static void main(String[] args) throws ClassNotFoundException { parseTypeAnnotation(); parseMethodAnnotation(); parseConstructAnnotation(); } }
以上摘自:
http://www.tmser.com/?post=34&page=4
3.jpa注解:声明一个pojo,并且表明其余数据库中表,字段的对应关系
使用方式:
1.设置Pojo为实体
1. @Entity //标识这个pojo是一个jpa实体
2. public class Users implements Serializable {
3. }
2.设置表名
1. @Entity
2. @Table(name = "users") //指定表名为users
3. public class Users implements Serializable {
4. }
3.设置主键
1. public class Users implements Serializable {
2. @Id
3. private String userCode;
4. 设置字段类型
通过@Column注解设置,包含的设置如下
.name:字段名
.unique:是否唯一
.nullable:是否可以为空
.inserttable:是否可以插入
.updateable:是否可以更新
.columnDefinition: 定义建表时创建此列的DDL
.secondaryTable: 从表名。如果此列不建在主表上(默认建在主表),该属性定义该列所在从表的名字。
1. @Column(name = "user_code", nullable = false, length=32)//设置属性userCode对应的字段为user_code,长度为32,非空
2. private String userCode;
3. @Column(name = "user_wages", nullable = true, precision=12, scale=2)//设置属性wages对应的字段为user_wages,12位数字可保留两位小数,可以为空
4. private double wages;
5. @Temporal(TemporalType.DATE)//设置为时间类型
6. private Date joinDate;
5.字段排序
在加载数据的时候可以为其指定顺序,使用@OrderBy注解实现
1. @Table(name = "USERS")
2. public class User {
3. @OrderBy(name = "group_name ASC, name DESC")
4. private List books = new ArrayList();
5. }
6.主键生成策略
1. public class Users implements Serializable {
2. @Id
3. @GeneratedValue(strategy=GenerationType.IDENTITY)//主键自增,注意,这种方式依赖于具体的数据库,如果数据库不支持自增主键,那么这个类型是没法用的
4. @Column(name = "user_id", nullable = false)
5. private int userId;
6.
7.
8. public class Users implements Serializable {
9. @Id
10. @GeneratedValue(strategy=GenerationType.TABLE)//通过一个表来实现主键id的自增,这种方式不依赖于具体的数据库,可以解决数据迁移的问题
11. @Column(name = "user_code", nullable = false)
12. private String userCode;
13.
14.
15. public class Users implements Serializable {
16. @Id
17. @GeneratedValue(strategy=GenerationType.SEQUENCE)//通过Sequence来实现表主键自增,这种方式依赖于数据库是否有SEQUENCE,如果没有就不能用
18. @SequenceGenerator(name="seq_user")
19. @Column(name = "user_id", nullable = false)
20. private int userId;
7.一对多映射关系
有T_One和T_Many两个表,他们是一对多的关系,注解范例如下
主Pojo
1. @Entity
2. @Table(name = "T_ONE")
3. public class One implements Serializable {
4. private static final long serialVersionUID = 1L;
5. @Id
6. @Column(name = "ONE_ID", nullable = false)
7. private String oneId;
8. @Column(name = "DESCRIPTION")
9. private String description;
10. @OneToMany(cascade = CascadeType.ALL, mappedBy = "oneId")//指向多的那方的pojo的关联外键字段
11. private Collection<Many> manyCollection;
子Pojo
1. @Entity
2. @Table(name = "T_MANY")
3. public class Many implements Serializable {
4. private static final long serialVersionUID = 1L;
5. @Id
6. @Column(name = "MANY_ID", nullable = false)
7. private String manyId;
8. @Column(name = "DESCRIPTION")
9. private String description;
10.
11. @JoinColumn(name = "ONE_ID", referencedColumnName = "ONE_ID")//设置对应数据表的列名和引用的数据表的列名
12. @ManyToOne//设置在“一方”pojo的外键字段上
13. private One oneId;
8.多对多映射关系
貌似多对多关系不需要设置级联,以前用hibernate的时候着实为多对多的级联头疼了一阵子,JPA的多对多还需要实际的尝试一下才能有所体会。
估计JPA的多对多也是可以转换成两个一对多的。
第一个Pojo
1. @Entity
2. @Table(name = "T_MANYA")
3. public class ManyA implements Serializable {
4. private static final long serialVersionUID = 1L;
5. @Id
6. @Column(name = "MANYA_ID", nullable = false)
7. private String manyaId;
8. @Column(name = "DESCRIPTION")
9. private String description;
10. @ManyToMany
11. @JoinTable(name = "TMANY1_TMANY2", joinColumns = {@JoinColumn(name = "MANYA_ID", referencedColumnName = "MANYA_ID")}, inverseJoinColumns = {@JoinColumn(name = "MANYB_ID", referencedColumnName = "MANYB_ID")})
12. private Collection<ManyB> manybIdCollection;
第二个Pojo
1. @Entity
2. @Table(name = "T_MANYB")
3. public class ManyB implements Serializable {
4. private static final long serialVersionUID = 1L;
5. @Id
6. @Column(name = "MANYB_ID", nullable = false)
7. private String manybId;
8. @Column(name = "DESCRIPTION")
9. private String description;
10. @ManyToMany(mappedBy = "manybIdCollection")
11. private Collection<ManyA> manyaIdCollection;
9.一对一映射关系
主Pojo
1. @Entity
2. @Table(name = "T_ONEA")
3. public class OneA implements Serializable {
4. private static final long serialVersionUID = 1L;
5. @Id
6. @Column(name = "ONEA_ID", nullable = false)
7. private String oneaId;
8. @Column(name = "DESCRIPTION")
9. private String description;
10. @OneToOne(cascade = CascadeType.ALL, mappedBy = "oneA")//主Pojo这方的设置比较简单,只要设置好级联和映射到从Pojo的外键就可以了。
11. private OneB oneB;
从Pojo
1. @Entity
2. @Table(name = "T_ONEB")
3. public class OneB implements Serializable {
4. private static final long serialVersionUID = 1L;
5. @Id
6. @Column(name = "ONEA_ID", nullable = false)
7. private String oneaId;
8. @Column(name = "DESCRIPTION")
9. private String description;
10. @JoinColumn(name = "ONEA_ID", referencedColumnName = "ONEA_ID", insertable = false, updatable = false)//设置从方指向主方的关联外键,这个ONEA_ID其实是表T_ONEA的主键
11. @OneToOne
12. private OneA oneA;
10 大字段
1. @Lob //对应Blob字段类型
2. @Column(name = "PHOTO")
3. private Serializable photo;
4. @Lob //对应Clob字段类型
5. @Column(name = "DESCRIPTION")
6. private String description;
11.瞬时字段
不需要与数据库映射的字段,在保存的时候不需要保存倒数据库
1. @Transient
2. private int tempValue;
3.
4. public int getTempValue(){
5. get tempValue;
6. }
7.
8. public void setTempValue(int value){
9. this.tempValue = value;
10. }
以上转自:http://blog.csdn.net/sensego/article/details/6082420