권장(무료): Java 기본 튜토리얼
Reflection은 다양한 오픈 소스 프로젝트에서 널리 사용되는 Java의 고급 기술입니다. . 예를 들어 Spring, Tomcat, Jetty 및 기타 프로젝트는 모두 리플렉션을 광범위하게 사용합니다.
Java 프로그래머로서 리플렉션을 잘 사용하면 기술 수준도 향상될 수 있을 뿐만 아니라 더 나은 프로젝트를 개발할 수 있습니다.
하지만 많은 사람들이 리플렉션에 대해 들어봤지만 어디에 사용해야 하는지는 모릅니다.
그럼 실제 작업부터 시작하여 리플렉션을 사용하여 객체를 MongoDb의 데이터 구조로 변환해 보겠습니다. 이 예제를 이해하고 나면 리플렉션이 어떻게 사용되는지 이해하게 될 것입니다.
전자상거래 시스템에서는 쿼리 성능을 향상시키기 위해 일부 데이터를 MongoDb에 저장해야 합니다. 하지만 그 전에 먼저 데이터를 MongoDb 구조로 변환해야 합니다. 즉, Java 객체를 문서로 변환해야 합니다.
예를 들어 주문 정보를 MongoDb에 저장하려면 주문 개체를 Document로 변환해야 합니다.
그러나 이런 방식으로 각 엔터티 클래스는 2Doc() 메서드를 개발해야 합니다. 이 방법에는 기술적 내용이 없으며 다양한 필드를 문서에 넣습니다. 그리고 필드가 너무 많으면 주의하지 않으면 잘못된 코드를 작성하게 될 것입니다.
public class Order { private Long id; private Long userId; private String orderNo; private BigDecimal amount; private String createTime; private String updateTime; // 省略无数字段 // 转换方法:订单转doc public Document order2Doc(Order order) { Document doc = new Document(); doc.put("id", order.getId()); doc.put("userId", order.getUserId()); doc.put("orderNo", order.getOrderNo()); doc.put("amount", order.getAmount()); doc.put("createTime", order.getCreateTime()); doc.put("updateTime", order.getUpdateTime()); // 省略无数put... return doc; } }
게다가 MongoDb에서 데이터를 가져와서 Document를 다시 Java 객체로 변환해야 한다는 것을 다시 느낄 수 있습니다.
public class Order { private Long id; private Long userId; private String orderNo; private BigDecimal amount; private String createTime; private String updateTime; // 省略无数字段 // 转换方法:doc转订单 public Order doc2Order(Document doc) { Order order = new Order(); order.setId((Long) doc.get("id")); order.setUserId((Long) doc.get("userId")); order.setOrderNo((String) doc.get("orderNo")); order.setAmount((BigDecimal) doc.get("amount")); order.setCreateTime((String) doc.get("createTime")); order.setUpdateTime((String) doc.get("updateTime")); // 省略无数set... return order; } }
단 하나의 주문 클래스는 너무 귀찮고, 그러한 클래스가 여러 개 있다는 것은 말할 것도 없고, 프로젝트에는 항상 새로운 요구 사항이 있습니다. 분야가 변경되면 큰 어려움을 겪게 될 수 있습니다. 전체 프로젝트.
따라서 오류를 줄이기 위해서는 이 두 가지 변환 방법을 최적화해야 하며, 이 최적화에서는 Java의 두 가지 고급 기능인 리플렉션과 제네릭을 사용합니다. 모두에게 좀 더 직관적인 이해를 주기 위해 두 가지 버전으로 나누어 보겠습니다.
첫 번째 버전은 리플렉션을 사용하여 엔터티 클래스의 변환 방법을 단순화합니다.두 번째 버전은 MongoDb 도구 클래스를 추출하기 위해 제네릭과 리플렉션을 사용합니다.
다음으로 단계별로 반복해 보겠습니다~
첫 번째 버전의 반복에서는 엔터티 클래스의 두 가지 변환 방법을 단순화하려고 합니다.
Java 객체를 문서로 변환하는 것부터 시작하고 다시 Order 클래스를 예로 들어 보겠습니다.
먼저 리플렉션을 통해 주문 클래스의 모든 필드 정보를 얻은 다음 루프를 사용하여 이러한 필드를 탐색합니다. 마지막으로 루프에서 필드의 액세스 권한을 해제하고 해당 필드를 문서에 넣습니다.
public class Order { // ...省略无数字段 public Document order2Doc(Order order) throws Exception { Document doc = new Document(); // 获取所有字段:通过 getClass() 方法获取 Class 对象,然后获取这个类所有字段 Field[] fields = order.getClass().getDeclaredFields(); for (Field field : fields) { // 开放字段操作权限 field.setAccessible(true); // 设置值 doc.put(field.getName(), field.get(order)); } return doc; } }
반사 변환 후 코드가 훨씬 간단해진 것을 볼 수 있습니다. 객체에 얼마나 많은 필드가 있는지, 얼마나 많은 Put 작업을 작성해야 하는지에 관계없이 이 몇 줄의 코드만으로 작업을 수행할 수 있습니다. Java 객체를 MongoDb 구조로 변환하는 것은 덜 번거로워 보입니다.
이 아이디어에 따라 두 번째 방법인 Document를 Java 객체로 변환해 보겠습니다.
public class Order { // ...省略无数字段 public Order doc2Order(Document doc) throws Exception { Order order = new Order(); for (String key : doc.keySet()) { // 获取字段 Field field = order.getClass().getDeclaredField(key); // 开放字段操作权限 field.setAccessible(true); // 设置值 field.set(order, doc.get(key)); } return order; } }
먼저 루프를 사용하여 문서를 순회하고 리플렉션을 사용하여 해당 필드를 얻은 다음 필드의 액세스 권한을 해제하고 문서 값을 객체의 필드로 설정합니다.
이 시점에서 두 엔터티 클래스의 변환 방법을 단순화하기 위해 리플렉션을 사용했으며 기본적으로 첫 번째 버전의 반복이 완료되었습니다. 남은 작업은 각 클래스를 복사하여 붙여넣고 모양을 바꾸는 것입니다.
그러나 이번 반복을 통해 작업량이 많이 줄어들었음에도 여전히 불합리한 부분이 많습니다.
우선 아직 중복된 코드가 많아요. 각 엔터티 클래스에는 두 가지 변환 메서드가 있지만 이 두 메서드의 핵심 논리는 동일하므로 어디든 복사할 필요가 없습니다.
그렇다면 이것은 엔터티 클래스가 수행해야 하는 기능이 아닙니다. 엔터티 클래스는 데이터를 일시적으로 유지하는 역할만 담당하며 지속성 기능에 대해서는 책임을 지지 않습니다. 데이터를 저장하는 위치와 변환해야 하는 데이터 구조는 엔터티 클래스와 아무 관련이 없습니다.
즉, 두 번째 반복을 수행해야 합니다.
간단히 말하면 제네릭은 처음에 특정 매개변수 유형을 지정할 필요가 없지만 사용할 때 매개변수 유형을 결정합니다.
제네릭과 리플렉션을 결합하면 중복 코드를 많이 줄이는 데 도움이 될 수 있습니다.
두 번째 반복을 어떻게 수행하는지 볼까요?
Java 객체를 문서로 변환하는 것부터 시작하세요. 먼저 일반 메서드를 선언한 다음 리플렉션을 통해 일반 클래스의 모든 필드 정보를 얻은 다음 루프를 사용하여 이러한 필드를 탐색합니다. 마지막으로 루프에서 필드를 문서에 넣습니다.
public class MongoDbUtils { // 定义泛型方法: // 1. 在返回值前,声明泛型参数 <参数名>; // 2. 传入参数时,指定一个泛型参数 public static <T> Document obj2Doc(T obj) throws Exception { Document doc = new Document(); // 获取所有字段:通过 getClass() 方法获取 Class 对象,然后获取这个类所有字段 Field[] fields = obj.getClass().getDeclaredFields(); for (Field field : fields) { // 开放字段操作权限 field.setAccessible(true); // 设置值 doc.put(field.getName(), field.get(obj)); } return doc; } }
제네릭을 추가한 후 중복 코드가 크게 줄어들고 엔터티 클래스를 더 이상 별도로 작성할 필요가 없습니다2Doc()
方法了。在使用的时候,只要调用 MongoDbUtils.obj2Doc()
.
동일한 아이디어에 따라 두 번째 방법인 Document를 Java 객체로 변환하는 방법을 계속해서 변환합니다.
public class MongoDbUtils { // 定义泛型方法: // 1. 在返回值前,声明泛型参数 <参数名>; // 2. 传入参数必须是 Class,但这个 Class 是泛型参数,不限制类型 public static <T> T doc2Obj(Document doc, Class<T> clazz) throws Exception { // 实例化泛型对象 T obj = clazz.newInstance(); for (String key : doc.keySet()) { // 获取字段 Field field = clazz.getDeclaredField(key); // 开放字段操作权限 field.setAccessible(true); // 设置值 field.set(obj, doc.get(key)); } return obj; } }
首先,我们定义实例化一个泛型对象;然后,我们使用循环遍历 Document;最后,在循环中,使用反射获取相应的字段,把 Document 的值设置到泛型对象的字段里。
第二版的迭代就基本完成了。我们在第一版迭代的基础上,加入了泛型,得到了一个工具类 MongoDbUtils
,这个工具类得到结果和以前完全一样,你可以看下测试代码。
public static void main(String[] args) throws Exception { Order order = new Order(); order.setId(0L); order.setUserId(0L); order.setOrderNo("1"); order.setAmount(new BigDecimal("0")); order.setCreateTime("2"); order.setUpdateTime("3"); System.out.println("原始数据:" + order); Document document = MongoDbUtils.obj2Doc(order); System.out.println("转换doc数据:" + document); Order order1 = MongoDbUtils.doc2Obj(document, Order.class); System.out.println("转换java数据:" + order1); } 运行结果: 原始数据:Order(id=0, userId=0, orderNo=1, amount=0, createTime=2, updateTime=3) 转换doc数据:Document{{id=0, userId=0, orderNo=1, amount=0, createTime=2, updateTime=3}} 转换java数据:Order(id=0, userId=0, orderNo=1, amount=0, createTime=2, updateTime=3)
这样一来,我们就不用保留实体类上的转换方法了,剩下的工作就是删代码。
MongoDb 和 Java 对象的互相转换就完成了。我们做了两次迭代,第一次迭代利用了反射,把大量手动 set/get 操作给去掉了;第二次迭代在原来的基础上,加入了泛型的应用,又去掉了一堆重复代码。
위 내용은 Java는 리플렉션을 사용하여 객체를 MongoDb 구조로 변환합니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!