Tabla de contenido
Una anotación personalizada
1. Metaanotación
Necesitamos agregar varias metanotaciones a las anotaciones personalizadas.
@Target
@Retention
@Inherited
@Documented
1.1 Breve introducción
@Target
se usa para declarar dónde se puede usar la anotación actual
valor | describir |
---|---|
Tipo de elemento.TIPO | Se aplica a clases, interfaces (incluidos los tipos de anotaciones) y enumeraciones. |
Tipo de elemento.CAMPO | Se aplica a propiedades (incluidas constantes en enumeraciones) |
Tipo de elemento.MÉTODO | Aplicar al método |
Tipo de elemento.PARÁMETRO | Parámetros formales aplicados a los métodos. |
Tipo de elemento.CONSTRUCTOR | aplicado al constructor |
Tipo de elemento.LOCAL_VARIABLE | aplicado a variables locales |
Tipo de elemento.ANNOTATION_TYPE | Se aplica a los tipos de anotaciones |
Tipo de elemento.PAQUETE | aplicar al paquete |
Tipo de elemento.TYPE_PARAMETER | aplicado a variables de tipo |
Tipo de elemento.TYPE_USE | Se aplica a cualquier declaración que utilice un tipo (como tipos en declaraciones de declaración, genéricos y declaraciones de conversión) |
@Retention
indica el ciclo de vida de la anotación.
tipo de ciclo de vida | describir |
---|---|
Política de retención.FUENTE | descartado en el momento de la compilación y no incluido en el archivo de clase |
Política de retención. CLASE | Descartado cuando se carga JVM, incluido en el archivo de clase, valor predeterminado |
Política de retención.RUNTIME | Cargado por la JVM, incluido en el archivo de clase y se puede obtener en tiempo de ejecución |
@Inherited
indica que se utiliza la anotación @Inherited, y las subclases de la clase marcada también tendrán esta anotación.
@Document
indica que el elemento marcado por esta anotación puede documentarse mediante Javadoc o herramientas similares.
Generalmente, basta con utilizar las tres primeras al declarar anotaciones personalizadas.
2 Anotación de declaración
// {} 中可以声明多个Target类型, 这个注解我们只用在类的属性上, 只注明这一个值即可
@Target({
ElementType.FIELD})
// 在运行时使用
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface ExcelValid {
// 注解的属性
// 属性声明格式 : 数据类型 属性名() default 默认值;
// 在调用获取属性值的时候 直接通过 ' 注解对象.属性名()' 的形式
int length() default 0;
DataTypeEnum type() default DataTypeEnum.String;
boolean notNull() default true;
String lengthMessage() default "";
String typeMessage() default "";
String notNullMessage() default "";
}
clase de enumeración
public enum DataTypeEnum {
Byte("Byte"),
Short("Short"),
Integer("Integer"),
Long("Long"),
Float("Float"),
Double("Double"),
String("String"),
BigDecimal("BigDecimal"),
Boolean("Boolean");
private final String value;
private DataTypeEnum(String value) {
this.value = value;
}
public String value() {
return this.value;
}
Esta anotación se declara
2. Herramientas de verificación
Escribir una clase de herramienta de validación
/**
* 导入excel参数校验
*/
public class ExcelValidUtil {
/**
* Excel导入字段校验
*
* @param object 校验的JavaBean 其属性须有自定义注解
*/
public static void Excelvalid(Object object) throws RuntimeException {
valid(object,0);
}
public static void Excelvalid(Object object, int size) throws RuntimeException {
valid(object,size);
}
private static void valid(Object object,int size) throws RuntimeException {
String prefix = "";
if (size > 0) {
prefix = "第" + size + "条数据";
}
// 通过反射获取类的所有属性字段
Field[] fields = object.getClass().getDeclaredFields();
for (Field field : fields) {
//设置可访问
field.setAccessible(true);
// 进行判断 如果属性上有 @ExcelIgnore 注解或者没有 @ExcelProperty则表示该字段不参数映射, 跳过
if (field.isAnnotationPresent(ExcelIgnore.class) || !field.isAnnotationPresent(ExcelProperty.class)) {
continue;
}
//属性的值
Object fieldValue = null;
try {
fieldValue = field.get(object);
} catch (IllegalAccessException e) {
throw new RuntimeException("导入参数检查失败");
}
//是否包含自定义校验注解
boolean hasValid = field.isAnnotationPresent(ExcelValid.class);
if (hasValid ) {
// 获取自定义注解
ExcelValid annotation = field.getAnnotation(ExcelValid.class);
// 非空校验
boolean notNull = annotation.notNull(); // 获取注解notNull属性的值
if (notNull && Objects.isNull(fieldValue)) {
throw new RuntimeException(prefix + " " +annotation.notNullMessage());
}
// 类型校验
DataTypeEnum type = annotation.type(); // 获取注解type属性的值
if (!validType(type,fieldValue)) {
throw new RuntimeException(prefix + " " +annotation.typeMessage());
}
// 长度校验
int length = annotation.length(); // 获取注解length属性的值
if (length > 0) {
if (length < String.valueOf(fieldValue).length()) {
throw new RuntimeException(prefix + " " +annotation.lengthMessage());
}
}
}
}
}
// 类型转换校验
private static Boolean validType(DataTypeEnum type,Object fieldValue) {
try {
switch (type){
case Byte: Byte.valueOf(String.valueOf(fieldValue)); break;
case Short: Short.valueOf(String.valueOf(fieldValue)); break;
case Integer: Integer.valueOf(String.valueOf(fieldValue)); break;
case Long: Long.valueOf(String.valueOf(fieldValue)); break;
case Float: Float.valueOf(String.valueOf(fieldValue)); break;
case Double: Double.valueOf(String.valueOf(fieldValue)); break;
case String: String.valueOf(fieldValue); break;
case BigDecimal: new BigDecimal(String.valueOf(fieldValue)); break;
case Boolean: Boolean.valueOf(String.valueOf(fieldValue)); break;
default: break;
}
}catch (Exception e){
// 转换失败返回false
return false;
}
return true;
}
}
3. Verificación
3.1 Usar anotaciones personalizadas en plantillas de Excel
@Data
@ColumnWidth(25)
@HeadRowHeight(20)
@ContentRowHeight(18)
public class GoodsExcel implements Serializable {
private static final long serialVersionUID = 1L;
@ExcelProperty("租户编号(可空)")
@ExcelValid(length = 255,lengthMessage = "分类编号 过长",
notNull = false,
type = DataTypeEnum.String,typeMessage = "分类编号 数据格式异常")
private String tenantId;
// 其中notnull 默认值是 true, 可空字段要填成 false
// type 默认类型是string, 可省略不写
// 默认值信息可省略
@ExcelProperty("货品名称")
@ExcelValid(length = 255,lengthMessage = "货品名称 过长",
notNullMessage = "货品名称 不可为空"
)
private String goodsName;
// 没有 ExcelProperty 注解 不会校验该字段
@ColumnWidth(30)
@ExcelValid(length = 2,lengthMessage = "是否一物一码 过长",
notNullMessage = "是否一物一码 不可为空"
)
private String isNotEditStr;
// 有ExcelIgnore注解 不会校验该字段
@ExcelProperty("是否一物一码(是/否)")
@ExcelIgnore
private Integer isNotEdit;
}