自定义注解
- 格式:docx
- 大小:1.29 MB
- 文档页数:15
java自定义注解动态解析获取方法参数值《Java自定义注解动态解析获取方法参数值》在Java编程中,注解是一种非常有用的工具,它可以用来给程序元素添加元数据。
在一些情况下,我们可能需要动态解析获取方法的参数值,这就需要使用自定义注解来实现。
本文将围绕这一主题展开讨论,并逐步深入探讨如何在Java中实现动态解析获取方法参数值的过程。
1. 初始理解:什么是自定义注解自定义注解是一种由程序员创建的注解类型,它可以用来给程序元素打上标记,从而能够在运行时通过反射对这些注解进行解析和处理。
在Java中,自定义注解通常通过 @interface 关键字来定义,可以包含成员变量、方法等信息。
2. 深入探讨:自定义注解的结构和定义在讨论如何动态解析获取方法参数值之前,我们首先要了解自定义注解的结构和定义方式。
一个标准的自定义注解包括注解名称、成员变量和相关的注解方法。
通过给出一些实际的例子,在这一部分我们将详细讲解如何定义一个自定义注解,并讨论其中的注意事项和最佳实践。
3. 动态解析获取方法参数值的需求场景动态解析获取方法参数值的需求通常出现在一些特定的业务场景中,例如在AOP编程、参数校验、日志记录等方面。
在这一部分,我们将围绕这些需求场景,详细分析为什么需要动态获取方法参数值,以及它的实际应用场景和作用。
4. 实现过程:使用自定义注解实现动态解析获取方法参数值在这一部分,我们将通过具体的代码实例,演示如何使用自定义注解来实现动态解析获取方法参数值。
我们将讨论自定义注解的定义和使用方式,以及如何在运行时通过反射来获取方法参数值。
我们还将讨论其中涉及到的技术难点和解决方案。
5. 总结回顾:对Java自定义注解动态解析获取方法参数值的全面理解通过本文的讨论,我们已经深入地了解了自定义注解的定义和使用,以及动态解析获取方法参数值的实现过程。
在这一部分,我们将对本文内容进行总结和回顾,从而全面、深刻和灵活地理解这一主题。
java自定义注解在excel导出时的使用在Java中,自定义注解是一种用于在程序中进行标记的机制。
通过定义自己的注解,可以为类、方法、字段等元素添加元数据,用于描述它们的特性和行为。
在Excel导出时,自定义注解可以用来定义导出的字段和格式,并且可以通过反射机制来读取注解信息,实现自动导出的功能。
下面是一个简单的自定义注解示例:```javaimport ng.annotation.*;String name( default ""; // 导出字段的名称int width( default 20; // 导出字段的宽度String format( default ""; // 导出字段的格式```定义了注解之后,可以在需要导出的类中使用该注解对字段进行标记。
例如:```javapublic class Userprivate String name;private int age;//其他字段和方法...```接下来,可以编写一个用于导出Excel的工具类。
该类可以使用反射来读取类的字段和注解信息,并根据注解信息生成相应的Excel文件。
以下是一个简单的Excel导出工具类示例:```javapublic class ExcelExportUtilpublic static <T> void exportToExcel(List<T> data, Class<T> clazz, String filePath)//创建工作簿和工作表Workbook workbook = new HSSFWorkbook(;Sheet sheet = workbook.createSheet("Sheet1");//获取类的字段和注解信息Field[] fields = clazz.getDeclaredFields(;for (int i = 0; i < fields.length; i++)Field field = fields[i];ExcelField excelField =field.getAnnotation(ExcelField.class);if (excelField != null)//获取注解信息String fieldName = (;int width = excelField.width(;//设置列宽sheet.setColumnWidth(i, width * 256);//创建表头单元格Row headerRow = sheet.getRow(0);if (headerRow == null)headerRow = sheet.createRow(0);}Cell headerCell = headerRow.createCell(i); headerCell.setCellValue(fieldName);}}//创建数据行for (int i = 0; i < data.size(; i++)T item = data.get(i);Row dataRow = sheet.getRow(i + 1);if (dataRow == null)dataRow = sheet.createRow(i + 1);}for (int j = 0; j < fields.length; j++)Field field = fields[j];if (field.isAccessible()try//获取字段值Object value = field.get(item);//创建数据单元格并填充数据Cell dataCell = dataRow.createCell(j); if (value instanceof String) dataCell.setCellValue((String) value); } else if (value instanceof Integer) dataCell.setCellValue((int) value);} else if (value instanceof Double) dataCell.setCellValue((double) value); }} catch (IllegalAccessException e)e.printStackTrace(;}}}}// 保存Excel文件try (FileOutputStream outputStream = newFileOutputStream(filePath))workbook.write(outputStream);} catch (IOException e)e.printStackTrace(;}}```在上面的示例中,exportToExcel方法接收一个泛型列表和类的字节码对象,通过反射来读取类的字段和注解信息,并根据注解信息生成Excel文件。
java字典类型转换自定义注解多层级解析在Java编程中,我们经常会遇到需要将字典类型转换为实际的Java对象的情况。
为了简化这一过程并提高代码的可读性,我们可以使用自定义注解来进行多层级解析。
首先,我们可以定义一个注解来标识需要进行字典类型转换的字段。
例如,我们可以使用`@Dictionary`注解来标记一个字段,表示该字段需要进行字典类型转换。
注解可以包含一些参数,用于指定字典类型和转换规则。
```java@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interface Dictionary {String type();String field() default "";}```接下来,我们可以编写一个工具类来进行字典类型转换和多层级解析的操作。
具体步骤如下:1. 遍历目标对象的字段,判断是否被`@Dictionary`注解标记。
2. 如果标记了`@Dictionary`注解,获取注解中指定的字典类型和转换规则。
3. 根据字典类型和转换规则,将字典值转换为实际的Java对象。
4. 如果字段是一个自定义对象,递归进行多层级解析。
代码示例:```javapublic class DictionaryUtils {public static void convert(Object obj) {Field[] fields = obj.getClass().getDeclaredFields();for (Field field : fields) {if (field.isAnnotationPresent(Dictionary.class)) {Dictionary dictionary = field.getAnnotation(Dictionary.class);String dictType = dictionary.type();String dictField = dictionary.field();// 获取字典值Object dictValue = getValueFromDictionary(dictType, dictField);// 设置字段值field.setAccessible(true);field.set(obj, dictValue);// 多层级解析if (field.getType().getClass().isAnnotationPresent(Dictionary.class)) { convert(field.get(obj));}}}}private static Object getValueFromDictionary(String dictType, String dictField) { // 在这里实现根据字典类型和转换规则获取字典值的逻辑// ...}}```使用示例:```javapublic class Demo {@Dictionary(type = "gender", field = "value")private String gender;@Dictionary(type = "grade", field = "name")private String grade;@Dictionary(type = "teacher", field = "")private Teacher teacher;public static void main(String[] args) {Demo demo = new Demo();DictionaryUtils.convert(demo);System.out.println(demo.gender); // 输出实际的性别值System.out.println(demo.grade); // 输出实际的年级值System.out.println(demo.teacher); // 输出转换后的Teacher对象}}```通过使用自定义注解和工具类,我们可以实现简单而灵活的字典类型转换和多层级解析功能,提高代码的可读性和可维护性。
java 自定义注解传参一、概述注解是 Java 编程中一个非常有用的特性,它允许开发者向代码添加元数据,而无需修改源代码。
自定义注解是开发者根据需求自定义的注解,可以用于标记代码中的特定部分,并在程序运行时进行各种处理。
在 Java 中,可以通过在代码中添加自定义注解并传递参数来扩展注解的功能。
二、注解定义要创建自定义注解,需要使用 Java 注解(@interface)在代码中定义一个或多个标记(annotation)。
标记可以包含属性(attribute),这些属性定义了注解的含义和行为。
例如,下面的代码定义了一个名为 CustomAnnotation 的自定义注解,该注解带有两个属性:name 和 value。
```java@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface CustomAnnotation {String name();String value();}```三、注解使用定义了自定义注解后,可以在代码中使用它来标记特定的元素。
使用自定义注解时,可以传递参数。
例如,下面的代码演示了如何使用上述定义的 CustomAnnotation 注解并传递参数:```java@CustomAnnotation(name = "MyCustomAnnotation", value = "This is a custom annotation")public void myMethod() {// 方法体}```四、注解处理器注解处理器是在程序运行时处理注解的组件。
当编译器编译代码时,它会将注解附加到被标记的方法上。
要执行运行时的注解处理,需要编写一个 Java 类来处理这些注解,并将其注册为注解处理器。
这可以通过实现一个接口来完成,该接口由 Java 自带的`javax.annotation.processing` 包提供。
java 自定义注解实现字段格式化的方法在过去的日子中,我们曾讨论过如何使用Java内置的注解来实现代码的某种功能。
然而,有时候我们需要根据项目需求创建自己的注解。
在这篇文章中,我们将详细介绍如何使用自定义注解实现字段格式化的方法。
1.介绍自定义注解的作用自定义注解,顾名思义,就是根据项目需求自己定义的注解。
它可以为我们提供更加灵活的代码控制,帮助我们实现诸如数据校验、字段格式化等功能。
在这个例子中,我们将使用自定义注解来实现字段格式化的目的。
2.演示如何创建自定义注解要创建一个自定义注解,我们需要遵循以下步骤:(1)定义一个接口,用于描述注解的信息。
(2)在需要使用注解的字段或方法上,使用`@interface`关键字添加注解。
下面是一个简单的自定义注解示例:```javaimport ng.annotation.ElementType;import ng.annotation.Retention;import ng.annotation.RetentionPolicy;import ng.annotation.Target;@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interface CustomFormat {String value() default "";}```在这个例子中,我们创建了一个名为`CustomFormat`的注解,并定义了一个名为`value`的属性,用于存储格式化后的字段值。
3.展示如何使用自定义注解实现字段格式化现在我们已经创建了自定义注解,接下来需要编写一个工具类,用于实现字段格式化的功能。
以下是一个简单的实现示例:```javaimport ng.reflect.Field;public class CustomFormatUtil {public static void formatField(Object obj) {if (obj == null) {return;}Class<?> clazz = obj.getClass();Field[] fields = clazz.getDeclaredFields();for (Field field : fields) {if (field.isAnnotationPresent(CustomFormat.class)) {CustomFormat customFormat =field.getAnnotation(CustomFormat.class);String format = customFormat.value();try {field.setAccessible(true);Object value = field.get(obj);String formattedValue = format.replace("{}", value.toString());field.set(obj, formattedValue);} catch (IllegalAccessException e) {e.printStackTrace();}}}}}```在这个例子中,我们编写了一个名为`formatField`的方法,用于遍历对象的所有字段。
自定义注解的实现方式自定义注解是Java语言中的一项重要功能,它可以为程序员提供更加灵活的编程方式。
自定义注解可以用于标记代码中的特定部分,以便在编译时或运行时进行处理。
本文将介绍自定义注解的实现方式。
一、定义注解定义注解需要使用Java语言提供的@interface关键字。
例如,我们可以定义一个名为@MyAnnotation的注解,如下所示:```@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interface MyAnnotation {String value() default "";}```在上面的代码中,我们使用了@Retention和@Target注解来指定注解的保留策略和作用目标。
@Retention注解用于指定注解的保留策略,它有三个取值:RetentionPolicy.SOURCE、RetentionPolicy.CLASS和RetentionPolicy.RUNTIME。
@Target 注解用于指定注解的作用目标,它有多个取值,包括ElementType.TYPE、ElementType.FIELD、ElementType.METHOD 等。
在@MyAnnotation注解中,我们定义了一个名为value的属性,它的默认值为""。
注解属性可以有多个,每个属性都可以指定默认值。
二、使用注解使用注解需要在代码中标记特定的部分。
例如,我们可以在一个方法上使用@MyAnnotation注解,如下所示:```@MyAnnotation("hello")public void sayHello() {System.out.println("Hello, world!");}```在上面的代码中,我们在sayHello()方法上使用了@MyAnnotation 注解,并指定了value属性的值为"hello"。
注解:@interface⾃定义注解的语法⾃定义注解: 使⽤@interface⾃定义注解时,⾃动继承了ng.annotation.Annotation接⼝,由编译程序⾃动完成其他细节。
在定义注解时,不能继承其他的注解或接⼝。
@interface⽤来声明⼀个注解,其中的每⼀个⽅法实际上是声明了⼀个配置参数。
⽅法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。
可以通过default来声明参数的默认值。
定义注解格式: public @interface 注解名 {定义体} 注解参数的可⽀持数据类型: 1.所有基本数据类型(int,float,boolean,byte,double,char,long,short) 2.String类型 3.Class类型 4.enum类型 5.Annotation类型 6.以上所有类型的数组 Annotation类型⾥⾯的参数该怎么设定: 第⼀,只能⽤public或默认(default)这两个访问权修饰.例如,String value();这⾥把⽅法设为defaul默认类型; 第⼆,参数成员只能⽤基本类型byte,short,char,int,long,float,double,boolean⼋种基本数据类型和 String,Enum,Class,annotations等数据类型,以及这⼀些类型的数组.例如,String value();这⾥的参数成员就为String; 第三,如果只有⼀个参数成员,最好把参数名称设为"value",后加⼩括号.例:下⾯的例⼦FruitName注解就只有⼀个参数成员。
简单的⾃定义注解和使⽤注解实例:package annotation;import ng.annotation.Documented;import ng.annotation.ElementType;import ng.annotation.Retention;import ng.annotation.RetentionPolicy;import ng.annotation.Target;/*** ⽔果名称注解* @author peida**/@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface FruitName {String value() default "";}package annotation;import ng.annotation.Documented;import ng.annotation.ElementType;import ng.annotation.Retention;import ng.annotation.RetentionPolicy;import ng.annotation.Target;/*** ⽔果颜⾊注解* @author peida**/@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface FruitColor {/*** 颜⾊枚举* @author peida**/public enum Color{ BULE,RED,GREEN};/*** 颜⾊属性* @return*/Color fruitColor() default Color.GREEN;}package annotation;import annotation.FruitColor.Color;public class Apple {@FruitName("Apple")private String appleName;@FruitColor(fruitColor=Color.RED)private String appleColor;public void setAppleColor(String appleColor) {this.appleColor = appleColor;}public String getAppleColor() {return appleColor;}public void setAppleName(String appleName) {this.appleName = appleName;}public String getAppleName() {return appleName;}public void displayName(){System.out.println("⽔果的名字是:苹果");}}注解元素的默认值: 注解元素必须有确定的值,要么在定义注解的默认值中指定,要么在使⽤注解时指定,⾮基本类型的注解元素的值不可为null。
SpringBoot自定义注解实现后台接收Json参数Spring Boot是一个用于构建独立的、基于生产级别的Java应用程序的框架。
它使得开发人员可以轻松地创建具有高效、可靠和可扩展特性的Spring应用程序。
在Spring Boot中,我们可以使用自定义注解来处理后台接收JSON参数的需求。
```javaimport org.springframework.web.bind.annotation.RequestBody;import ng.annotation.ElementType;import ng.annotation.Retention;import ng.annotation.RetentionPolicy;import ng.annotation.Target;```接下来,我们可以在Spring Boot的Controller中使用这个自定义注解来接收JSON参数。
下面是一个简单的例子:```javaimport org.springframework.web.bind.annotation.PostMapping;importorg.springframework.web.bind.annotation.RestController;public class UserController//处理用户添加的逻辑}```需要注意的是,为了使Spring Boot能够正确地将请求体中的JSON 数据转换为Java对象,我们需要在项目中引入相关的依赖。
可以在`pom.xml`文件中添加以下依赖:```xml<dependency><artifactId>jackson-databind</artifactId></dependency>```这个依赖将提供JSON与Java对象之间的转换功能。
总结来说,Spring Boot的自定义注解可以很方便地实现后台接收JSON参数的功能。
自定义注解封装注解继承注解自定义注解、封装注解和继承注解是Java编程中非常重要的概念。
它们可以帮助我们更好地组织和管理代码,提高代码的可读性和可维护性。
在本文中,我们将从简单到复杂的角度来探讨这些概念,以便读者能够更深入地理解它们的作用和用法。
1. 自定义注解自定义注解是Java语言中一种非常强大的特性。
通过自定义注解,我们可以为我们的代码添加元数据信息,从而使代码更加灵活和扩展。
在Java中,自定义注解使用@interface关键字来定义。
我们可以在注解中定义属性,这些属性可以在使用注解的地方进行配置。
例如:```javapublic @interface MyAnnotation {String value();}```在上面的例子中,我们定义了一个名为MyAnnotation的注解,并且添加了一个名为value的属性。
我们可以在使用该注解的地方对value属性进行配置,如下所示:```java@MyAnnotation(value = "Hello")public class MyClass {// ...}```通过自定义注解,我们可以为我们的代码添加更多的元数据信息,从而提高代码的可读性和可维护性。
2. 封装注解封装注解是指在一个注解中包含另一个注解。
通过封装注解,我们可以更好地组织和管理注解,使其更具有可扩展性和灵活性。
例如:```javapublic @interface MyMetaAnnotation {MyAnnotation value();}```在上面的例子中,我们定义了一个名为MyMetaAnnotation的注解,并且包含了一个名为value的属性,其类型为MyAnnotation。
这样一来,我们可以在使用MyMetaAnnotation的地方,同时配置MyAnnotation的属性。
这种封装使得我们可以更好地重用和组织注解,使其更加灵活和可扩展。
自定义元分转换注解什么是自定义元分转换注解?在Java编程中,注解(Annotation)是一种特殊的修饰符,用于给程序中的元素(类、方法、字段等)添加额外的元数据(Metadata)。
这些元数据可以被编译器、解析器或其他工具程序读取和使用。
注解提供了一种简单而强大的机制来描述代码的特性、行为和要求。
自定义元分转换注解是开发者自定义的注解,用于定义将数字元单位转换为分单位的规则。
这种规则常见于金融系统、计费系统等需要处理金额的应用程序中。
在这些系统中,经常需要对金额进行精确的计算,而分单位能够提供更高的精度。
为了更好地理解自定义元分转换注解,我们将通过以下几个步骤逐步回答相关问题:第一步:为什么需要自定义元分转换注解?在金融系统中,金额通常以元为单位进行表示,例如100元、10.5元等。
然而,由于元单位的精度有限,这在进行复杂的计算时可能会导致精度丢失。
为了避免这个问题,我们通常将金额转换为分单位进行计算。
例如,100元可以表示为10000分,10.5元可以表示为1050分。
在实际应用中,金额的元分转换是一个常见的需求。
为了方便开发者处理这种转换,我们可以定义一个自定义元分转换注解来规范这个过程。
第二步:如何自定义元分转换注解?在Java中,我们可以通过定义一个注解来实现自定义元分转换注解。
以下是一个自定义元分转换注解的示例:javaimport ng.annotation.*;@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.FIELD)public @interface YuanToFen {}在这个示例中,我们使用了Java的元注解(Meta-Annotation)来修饰这个自定义注解。
`@Retention`注解指定了这个注解的保留策略是运行时(Runtime Retention),这意味着它可以在程序运行时被反射读取。
`@Target`注解指定了这个注解的可用范围是字段(Field)。
spring AOP自定义注解方式实现日志管理今天继续实现AOP,到这里我个人认为是最灵活,可扩展的方式了,就拿日志管理来说,用Spring AOP 自定义注解形式实现日志管理。
废话不多说,直接开始!!!关于配置我还是的再说一遍。
在applicationContext-mvc.xml中要添加的<mvc:annotation-driven /><!-- 激活组件扫描功能,在包com.gcx及其子包下面自动扫描通过注解配置的组件 --><context:component-scan base-package="com.gcx" /><!-- 启动对@AspectJ注解的支持 --><!-- proxy-target-class等于true是强制使用cglib代理,proxy-target-class默认是false,如果你的类实现了接口就走JDK代理,如果没有,走cglib代理 --><!-- 注:对于单利模式建议使用cglib代理,虽然JDK动态代理比cglib代理速度快,但性能不如cglib --><!--如果不写proxy-target-class="true"这句话也没问题--><aop:aspectj-autoproxy proxy-target-class="true"/><!--切面--><bean id="systemLogAspect"class="com.gcx.annotation.SystemLogAspect"></bean>接下来开始编写代码。
创建日志类实体1public class SystemLog {2private String id;34private String description;56private String method;78private Long logType;910private String requestIp;1112private String exceptioncode;1314private String exceptionDetail;1516private String params;1718private String createBy;1920private Date createDate;2122public String getId() {23return id;24 }2526public void setId(String id) {27this.id = id == null ? null : id.trim();28 }2930public String getDescription() {31return description;32 }3334public void setDescription(String description) {35this.description = description == null ? null : description.trim();36 }3738public String getMethod() {39return method;40 }4142public void setMethod(String method) {43this.method = method == null ? null : method.trim();44 }4546public Long getLogType() {47return logType;48 }4950public void setLogType(Long logType) {51this.logType = logType;52 }5354public String getRequestIp() {55return requestIp;56 }5758public void setRequestIp(String requestIp) {59this.requestIp = requestIp == null? null: requestIp.trim();60 }6162public String getExceptioncode() {63return exceptioncode;64 }6566public void setExceptioncode(String exceptioncode) {67this.exceptioncode = exceptioncode == null ? null : exceptioncode.trim();68 }6970public String getExceptionDetail() {71return exceptionDetail;72 }7374public void setExceptionDetail(String exceptionDetail) {75this.exceptionDetail = exceptionDetail == null ? null : exceptionDetail.trim();76 }7778public String getParams() {79return params;80 }8182public void setParams(String params) {83this.params = params == null ? null : params.trim();84 }8586public String getCreateBy() {87return createBy;88 }8990public void setCreateBy(String createBy) {91this.createBy = createBy == null ? null : createBy.trim();92 }9394public Date getCreateDate() {95return createDate;96 }9798public void setCreateDate(Date createDate) {99this.createDate = createDate;100 }101 }编写dao接口1package com.gcx.dao;23import com.gcx.entity.SystemLog;45public interface SystemLogMapper {6int deleteByPrimaryKey(String id);78int insert(SystemLog record);910int insertSelective(SystemLog record);1112 SystemLog selectByPrimaryKey(String id);1314int updateByPrimaryKeySelective(SystemLog record);1516int updateByPrimaryKey(SystemLog record);17 }编写service层1package com.gcx.service;23import com.gcx.entity.SystemLog;45public interface SystemLogService {67int deleteSystemLog(String id);89int insert(SystemLog record);1011int insertTest(SystemLog record);1213 SystemLog selectSystemLog(String id);1415int updateSystemLog(SystemLog record);16 }编写service实现类serviceImpl1package com.gcx.service.impl;23import javax.annotation.Resource;45import org.springframework.stereotype.Service;67import com.gcx.annotation.Log;8import com.gcx.dao.SystemLogMapper;9import com.gcx.entity.SystemLog;10import com.gcx.service.SystemLogService;1112 @Service("systemLogService")13public class SystemLogServiceImpl implements SystemLogService { 1415 @Resource16private SystemLogMapper systemLogMapper;1718 @Override19public int deleteSystemLog(String id) {2021return systemLogMapper.deleteByPrimaryKey(id);22 }2324 @Override2526public int insert(SystemLog record) {2728return systemLogMapper.insertSelective(record);29 }3031 @Override32public SystemLog selectSystemLog(String id) {3334return systemLogMapper.selectByPrimaryKey(id);35 }3637 @Override38public int updateSystemLog(SystemLog record) {3940returnsystemLogMapper.updateByPrimaryKeySelective(record);41 }4243 @Override44public int insertTest(SystemLog record) {4546return systemLogMapper.insert(record);47 }4849 }到这里基本程序编写完毕下面开始自定义注解1package com.gcx.annotation;23import ng.annotation.*;45 @Target({ElementType.PARAMETER, ElementType.METHOD})6 @Retention(RetentionPolicy.RUNTIME)7 @Documented8public @interface Log {910/** 要执行的操作类型比如:add操作 **/11public String operationType() default "";1213/** 要执行的具体操作比如:添加用户 **/14public String operationName() default "";15 }下面编写切面1package com.gcx.annotation;23import ng.reflect.Method;4import java.util.Date;5import java.util.UUID;67import javax.annotation.Resource;8import javax.servlet.http.HttpServletRequest;9import javax.servlet.http.HttpSession;1011import ng.JoinPoint;12import ng.ProceedingJoinPoint;13import ng.annotation.After;14import ng.annotation.AfterReturning; 15import ng.annotation.AfterThrowing; 16import ng.annotation.Around;17import ng.annotation.Aspect;18import ng.annotation.Before;19import ng.annotation.Pointcut;20import org.slf4j.Logger;21import org.slf4j.LoggerFactory;22import ponent; 2324import com.gcx.entity.SystemLog;25import er;26import com.gcx.service.SystemLogService;27import com.gcx.util.JsonUtil;2829/**30 * @author杨建31 * @E-mail: email32 * @version创建时间:2015-10-19 下午4:29:0533 * @desc 切点类34*/3536 @Aspect37 @Component38public class SystemLogAspect {3940//注入Service用于把日志保存数据库41 @Resource //这里我用resource注解,一般用的是@Autowired,他们的区别如有时间我会在后面的博客中来写42private SystemLogService systemLogService;4344private static final Logger logger =LoggerFactory.getLogger(SystemLogAspect. class);4546//Controller层切点47 @Pointcut("execution (* com.gcx.controller..*.*(..))")48public void controllerAspect() {49 }5051/**52 * 前置通知用于拦截Controller层记录用户的操作53 *54 * @param joinPoint 切点55*/56 @Before("controllerAspect()")57public void doBefore(JoinPoint joinPoint) {58 System.out.println("==========执行controller前置通知===============");59if(logger.isInfoEnabled()){60 ("before " + joinPoint);61 }62 }6364//配置controller环绕通知,使用在方法aspect()上注册的切入点65 @Around("controllerAspect()")66public void around(JoinPoint joinPoint){67 System.out.println("==========开始执行controller环绕通知===============");68long start = System.currentTimeMillis();69try {70 ((ProceedingJoinPoint) joinPoint).proceed();71long end = System.currentTimeMillis();72if(logger.isInfoEnabled()){73 ("around " + joinPoint + "\tUse time : " + (end - start) + " ms!");74 }75 System.out.println("==========结束执行controller环绕通知===============");76 } catch (Throwable e) {77long end = System.currentTimeMillis();78if(logger.isInfoEnabled()){79 ("around " + joinPoint + "\tUse time : " + (end - start) + " ms with exception : " + e.getMessage());80 }81 }82 }8384/**85 * 后置通知用于拦截Controller层记录用户的操作86 *87 * @param joinPoint 切点88*/89 @After("controllerAspect()")90public void after(JoinPoint joinPoint) {9192/* HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();93 HttpSession session = request.getSession(); */94//读取session中的用户95// User user = (User) session.getAttribute("user");96//请求的IP97//String ip = request.getRemoteAddr();98 User user = new User();99 user.setId(1);100 user.setName("张三");101 String ip = "127.0.0.1";102try {103104 String targetName =joinPoint.getTarget().getClass().getName();105 String methodName =joinPoint.getSignature().getName();106 Object[] arguments = joinPoint.getArgs();107 Class targetClass = Class.forName(targetName);108 Method[] methods = targetClass.getMethods();109 String operationType = "";110 String operationName = "";111for (Method method : methods) {112if (method.getName().equals(methodName)) {113 Class[] clazzs = method.getParameterTypes(); 114if (clazzs.length == arguments.length) {115 operationType =method.getAnnotation(Log.class).operationType();116 operationName =method.getAnnotation(Log.class).operationName();117break;118 }119 }120 }121//*========控制台输出=========*//122 System.out.println("=====controller后置通知开始=====");123 System.out.println("请求方法:" +(joinPoint.getTarget().getClass().getName() + "." +joinPoint.getSignature().getName() + "()")+"."+operationType); 124 System.out.println("方法描述:" + operationName); 125 System.out.println("请求人:" + user.getName()); 126 System.out.println("请求IP:" + ip);127//*========数据库日志=========*//128 SystemLog log = new SystemLog();129 log.setId(UUID.randomUUID().toString());130 log.setDescription(operationName);131log.setMethod((joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()")+"."+operationType); 132 log.setLogType((long)0);133 log.setRequestIp(ip);134 log.setExceptioncode( null);135 log.setExceptionDetail( null);136 log.setParams( null);137 log.setCreateBy(user.getName());138 log.setCreateDate(new Date());139//保存数据库140 systemLogService.insert(log);141 System.out.println("=====controller后置通知结束=====");142 } catch (Exception e) {143//记录本地异常日志144 logger.error("==后置通知异常==");145 logger.error("异常信息:{}", e.getMessage());146 }147 }148149//配置后置返回通知,使用在方法aspect()上注册的切入点150 @AfterReturning("controllerAspect()")151public void afterReturn(JoinPoint joinPoint){152 System.out.println("=====执行controller后置返回通知=====");153if(logger.isInfoEnabled()){154 ("afterReturn " + joinPoint);155 }156 }157158/**159 * 异常通知用于拦截记录异常日志160 *161 * @param joinPoint162 * @param e163*/164 @AfterThrowing(pointcut = "controllerAspect()", throwing="e") 165public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {166/*HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();167 HttpSession session = request.getSession();168 //读取session中的用户169 User user = (User)session.getAttribute(WebConstants.CURRENT_USER);170 //获取请求ip171 String ip = request.getRemoteAddr(); */172//获取用户请求方法的参数并序列化为JSON格式字符串173174 User user = new User();175 user.setId(1);176 user.setName("张三");177 String ip = "127.0.0.1";178179 String params = "";180if (joinPoint.getArgs() != null &&joinPoint.getArgs().length > 0) {181for ( int i = 0; i < joinPoint.getArgs().length; i++) {182 params +=JsonUtil.getJsonStr(joinPoint.getArgs()[i]) + ";";183 }184 }185try {186187 String targetName =joinPoint.getTarget().getClass().getName();188 String methodName =joinPoint.getSignature().getName();189 Object[] arguments = joinPoint.getArgs();190 Class targetClass = Class.forName(targetName);191 Method[] methods = targetClass.getMethods();192 String operationType = "";193 String operationName = "";194for (Method method : methods) {195if (method.getName().equals(methodName)) {196 Class[] clazzs = method.getParameterTypes(); 197if (clazzs.length == arguments.length) { 198 operationType =method.getAnnotation(Log.class).operationType();199 operationName =method.getAnnotation(Log.class).operationName();200break;201 }202 }203 }204/*========控制台输出=========*/205 System.out.println("=====异常通知开始=====");206 System.out.println("异常代码:" +e.getClass().getName());207 System.out.println("异常信息:" + e.getMessage());208 System.out.println("异常方法:" +(joinPoint.getTarget().getClass().getName() + "." +joinPoint.getSignature().getName() + "()")+"."+operationType);209 System.out.println("方法描述:" + operationName);210 System.out.println("请求人:" + user.getName());211 System.out.println("请求IP:" + ip);212 System.out.println("请求参数:" + params);213/*==========数据库日志=========*/214 SystemLog log = new SystemLog();215 log.setId(UUID.randomUUID().toString());216 log.setDescription(operationName);217 log.setExceptioncode(e.getClass().getName());218 log.setLogType((long)1);219 log.setExceptionDetail(e.getMessage());220log.setMethod((joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));221 log.setParams(params);222 log.setCreateBy(user.getName());223 log.setCreateDate(new Date());224 log.setRequestIp(ip);225//保存数据库226 systemLogService.insert(log);227 System.out.println("=====异常通知结束=====");228 } catch (Exception ex) {229//记录本地异常日志230 logger.error("==异常通知异常==");231 logger.error("异常信息:{}", ex.getMessage());232 }233/*==========记录本地异常日志==========*/234 logger.error("异常方法:{}异常代码:{}异常信息:{}参数:{}", joinPoint.getTarget().getClass().getName() +joinPoint.getSignature().getName(), e.getClass().getName(),e.getMessage(), params);235236 }237238 }我这里写的比较全,前置通知,环绕通知,后置通知,异常通知,后置饭后通知,都写上了,在我们实际编写中不写全也没事,我习惯上把记录日志的逻辑写在后置通知里面,我看网上也有些在前置通知里面的,但我感觉写在后置通知里比较好。