`

Gson切面日志实践

阅读更多
背景
  应用切面做日志记录,记录操作实体详情时可以使用JSON格式,这里是我使用Gson包做切面日志的一些实践,总结了遇到的问题。


软件包和学习方法
  这里使用google的Gson包做JSON转换,这里是项目的地址,可以查看上面的API和User Guide。务必将源码和API配置好,文档中的记录不是很完善,很多时候需要查看源码。
  注意,我使用的是2.2版,因为较早的1.4版本的FieldAttributes类中没有getDeclaringClass()这个方法,这个方法是获取field所属的类,在我的排除策略中会用到。
 

排除策略
  最简单的gson转换可以是这样的,但却没有多少实际的作用。切面日志时,一个实体和其他实体存在关联,这时候就需要通过自定义排除策略决定如何转换关联对象,否则可能出现“爆炸式”的json字符串。
Gson gson = new Gson();
int[] ints = {1, 2, 3, 4, 5};
String[] strings = {"abc", "def", "ghi"};

// Serialization
gson.toJson(ints);     ==> prints [1,2,3,4,5]
gson.toJson(strings);  ==> prints ["abc", "def", "ghi"]

  下面是我定义的一个排除策略的类,能基本满足需求,从内网搬过来的,未测试
package com.lingceng.magic.logutil;

import org.apache.commons.lang.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;

public class TargetStrategy implements ExclusionStrategy {
	private static Logger log = LoggerFactory.getLogger(TargetStrategy.class);
	private Class<?> target;
	private String[] fields;
	private Class<?>[] clazz;
	private boolean reverse;

	public TargetStrategy(Class<?> target) {
		super();
		this.target = target;
	}

	@Override
	public boolean shouldSkipClass(Class<?> class1) {
		return false;
	}

	@Override
	public boolean shouldSkipField(FieldAttributes fieldattributes) {
		Class<?> owner = fieldattributes.getDeclaringClass();
		Class<?> c = fieldattributes.getDeclaredClass();
		String f = fieldattributes.getName();
		boolean isSkip = false;
		
		if (owner == target) {
			if (ArrayUtils.contains(fields, f)) {
				log.debug("fitler field:{} for class:{}", f, owner);
				isSkip = true;
			}
			if (ArrayUtils.contains(clazz, c)) {
				log.debug("fitler class:{} for class:{}", c, owner);
				isSkip = true;
			}
			if (reverse) {
				isSkip = !isSkip;
			}
		}

		return isSkip;
	}

	public void setFields(String[] fields) {
		this.fields = fields;
	}

	public void setClazz(Class<?>[] clazz) {
		this.clazz = clazz;
	}

	public void setReverse(boolean reverse) {
		this.reverse = reverse;
	}
}


使用的时候是这样的
TargetStrategy ts = new TargetStrategy(Student.class);
//这里是仅转换Student中的id和name属性
ts.setFields(new String[] {"id", "name"});
ts.setReverse(true);

Gson gson = new GsonBuilder().setExcludeStrategy(ts).create();
gson.toJson(teacher);


HibernateProxy异常处理
  在使用Hibernate时,那么很可能遇到这样的错误
java.lang.UnsupportedOperationException: Attempted to serialize java.lang.Class: org.hibernate.proxy.HibernateProxy. Forgot to register a type adapter?
  因为gson在转换时是使用的反射机制,当获取的实体对象还在hibernate代理的时候,例如刚通过Id获取到,这时候获取到的便是代理对象HibernateProxy。这和直接调用实体对象的get方法不同,获取对象的属性就不能起作用。
  解决的方法便是将代理对象实例化,见下面的代码
/**
 * This TypeAdapter unproxies Hibernate proxied objects, and serializes them
 * through the registered (or default) TypeAdapter of the base class.
 */
public class HibernateProxyTypeAdapter extends TypeAdapter<HibernateProxy> {

    public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {
        @Override
        @SuppressWarnings("unchecked")
        public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
            return (HibernateProxy.class.isAssignableFrom(type.getRawType()) ? (TypeAdapter<T>) new HibernateProxyTypeAdapter(gson) : null);
        }
    };
    private final Gson context;

    private HibernateProxyTypeAdapter(Gson context) {
        this.context = context;
    }

    @Override
    public HibernateProxy read(JsonReader in) throws IOException {
        throw new UnsupportedOperationException("Not supported");
    }

    @SuppressWarnings({"rawtypes", "unchecked"})
    @Override
    public void write(JsonWriter out, HibernateProxy value) throws IOException {
        if (value == null) {
            out.nullValue();
            return;
        }
        // Retrieve the original (not proxy) class
        Class<?> baseType = Hibernate.getClass(value);
        // Get the TypeAdapter of the original class, to delegate the serialization
        TypeAdapter delegate = context.getAdapter(TypeToken.get(baseType));
        // Get a filled instance of the original class
        Object unproxiedValue = ((HibernateProxy) value).getHibernateLazyInitializer()
                .getImplementation();
        // Serialize the value
        delegate.write(out, unproxiedValue);
    }
}

使用的时候将该TypeAdapter的Factory注册到GsonBuilder,上面的代码变为
Gson gson = new GsonBuilder().setExcludeStrategy(ts)
.registerTypeAdapterFactory(HibernateProxyTypeAdapter.FACTORY)
.create();
gson.toJson(teacher);



Javascript格式化
  默认情况下,在页面上显示json字符串时是连在一起的,格式化一下可以便于阅读:
// get text for textarea, do not use text()
var msg= $("#jsonText").val();
// parse json
msg = JSON.parse(msg);
// return format string
msg = JSON.stringify(msg, null, 4);

这里要注意的是IE8在转换的时候会出现问题,所以需要引入json.js,将里面的JSON换为JSON2来使用,这时候代码便是这样的
// get text for textarea, do not use text()
var msg= $("#jsonText").val();
// parse json
msg = JSON2.parse(msg);
// return format string
msg = JSON2.stringify(msg, null, 4);
分享到:
评论

相关推荐

    Java Web SSM(Spring SpringMVC Mybaits)基础框架搭建

    AOP则用于实现日志记录、权限验证等跨切面的功能。 2. **SpringMVC**:作为Spring的Web模块,SpringMVC处理HTTP请求并返回响应。它包括前端控制器DispatcherServlet、处理器映射器HandlerMapping、处理器适配器...

    《Spring 3.x 企业应用开发实战》lib包

    2. **面向切面编程(Aspect-Oriented Programming, AOP)**:Spring的AOP模块允许开发者定义“切面”,将关注点如日志、事务管理等与业务逻辑分离。这提供了更好的代码组织和模块化。 3. **数据访问集成(Data ...

    spring框架开发相关jar包

    Spring框架是Java开发中最常用的轻量级开源框架之一,它为开发者提供了强大的依赖注入(Dependency Injection,DI)、面向切面编程(Aspect Oriented Programming,AOP)以及事务管理等功能,极大地提高了开发效率和...

    java学习shh框架jar包

    - AOP(面向切面编程):Spring提供切面编程能力,允许我们定义横切关注点,如日志、事务管理等。 - JDBC模板和数据源管理:Spring简化了数据库操作,通过JdbcTemplate和DataSource进行数据访问。 - MVC(模型-...

    Java基于SSM(Spring+SpringMVC+MyBatis)高速公路收费系统.zip

    Spring的AOP(面向切面编程)模块可以用来实现日志记录、安全控制等跨切面关注点。 2. **SpringMVC**:作为Spring的一部分,SpringMVC是一个用于构建Web应用的Model-View-Controller(MVC)框架。它负责接收HTTP...

    Srpingmvc 框架所需的全部jar

    6. **spring-aop.jar**:实现 AOP 面向切面编程的库,允许定义横切关注点,如日志、事务管理等,并将其模块化。 7. **spring-aspects.jar**:提供了与特定编程语言(如 AspectJ)集成的 AOP 支持。 8. **jstl.jar*...

    浙大健康打卡的学习交流项目_Java_下载.zip

    8. **Spring框架**:作为Java后端开发的主流框架,Spring可以简化项目开发,提供依赖注入、AOP(面向切面编程)等功能,可能被用在健康打卡服务的实现中。 9. **数据库操作**:如果项目需要存储用户信息或打卡记录...

    Spring 3.x 权威指南:实施Java EE 6 的利器

    其次,Spring的AOP(面向切面编程)允许开发者定义横切关注点,如日志、事务管理等,从而将这些通用功能与业务逻辑分离,提高代码复用。书中有专门章节讲述如何创建和使用自定义切面,以及如何结合Spring的事务管理...

    最全的ssm项目依赖包

    首先,Spring是一个开源的应用框架,它提供了对Java EE的全面控制,包括依赖注入(Dependency Injection,DI)、面向切面编程(Aspect-Oriented Programming,AOP)以及事务管理等核心功能。在SSM项目中,Spring作为...

    SSH整合用到的jar包

    总之,SSH整合涉及多个层面的技术,包括MVC设计模式、依赖注入、面向切面编程、对象关系映射等,而jar包的正确选用和管理是实现这一整合的基础。通过深入学习和实践,开发者可以充分利用SSH框架的强大功能,构建高效...

    json-lib-support-spring-源码.rar

    Spring 是一个广泛使用的 Java 应用框架,它提供了丰富的功能,包括依赖注入、AOP(面向切面编程)以及对各种数据访问技术的支持。 在深入解析源码之前,我们需要了解 JSON 和 Spring 的基本概念。JSON 是一种轻量...

    (转)java 常用工具包

    7. Spring Framework: 一个全面的后端开发框架,包括依赖注入、AOP(面向切面编程)、数据库访问等组件。Spring Boot简化了Spring的配置,使得快速开发变得更加容易。 8. Hibernate: ORM(对象关系映射)框架,允许...

    SSM资源依赖包

    Spring的核心特性包括依赖注入(DI),面向切面编程(AOP),以及各种容器和工具支持,这些都极大地提高了代码的可测试性和模块化程度。 Spring MVC是Spring框架的一部分,专门用于处理Web请求。它为开发者提供了...

    java预约挂号系统的后台WEB

    这些框架提供了快速开发、依赖注入和AOP(面向切面编程)等功能,简化了项目结构,提高了开发效率。 2. **数据库设计**:系统通常会使用MySQL、Oracle或PostgreSQL等关系型数据库存储用户信息、医生资料、预约记录...

    基于Java的书籍管理系统.zip

    4. MVC框架:如Spring MVC,提供一套完整的MVC解决方案,包含依赖注入、AOP(面向切面编程)等功能。 5. JSON处理:使用Jackson或Gson库进行JSON数据的序列化和反序列化,便于前后端数据交换。 6. 安全管理:Spring ...

    SSH所有的压缩包

    1. **Spring框架**:Spring是Java开发中的核心框架,它提供了依赖注入(Dependency Injection, DI)和面向切面编程(Aspect-Oriented Programming, AOP)的能力。Spring的IoC容器管理着应用对象的生命周期和配置,而...

    ssm框架整合必备包,同时附带json包

    而面向切面编程则提供了一种模块化代码的方式,使得业务逻辑与系统服务如日志、事务管理等可以分离。 2. **Spring MVC**:作为Spring框架的一部分,Spring MVC用于构建Web应用程序。它采用模型-视图-控制器(MVC)...

    java document

    1. **Spring Framework**:这是一个全面的企业级应用开发框架,提供了依赖注入、AOP(面向切面编程)、MVC(模型-视图-控制器)等特性,是Java后端开发的基石。 2. **Hibernate**:作为一款流行的ORM(对象关系映射...

    新起点音乐网-用户模块 (无问题) (过期了)

    在这个用户模块中,Spring可能被用来管理Bean,实现依赖注入,以及提供AOP(面向切面编程)来处理如日志、事务管理等功能。 3. **Spring Security**:对于用户身份验证和授权,Spring Security是一个强大的工具。它...

    spring小程序2

    Spring是一个广泛使用的Java企业级应用框架,它提供了依赖注入(DI)和面向切面编程(AOP)等功能,极大地简化了Java应用的开发。 描述中提到的“BbsSpringDemo”可能是一个论坛系统的示例项目,它使用Spring框架...

Global site tag (gtag.js) - Google Analytics