来自 SQL 视图的嵌套 JSON 响应
Nested JSON response from SQL View
我有一个 SQL 视图 (IdView
),它的值低于此值。我对此视图只有读取权限,对基础表没有任何访问权限。
+-------+-------+------------+------------+---------+-----------+----------------+
| ID | Name | Desc | Relation | ChildId | ChildName | ChildDesc |
+-------+-------+------------+------------+---------+-----------+----------------+
| 80121 | Car | Model A | Kits | 50123 | Bolt | Hexagonal Bolt |
| 80121 | Car | Model A | Kits | 50124 | Nut | 25mm Dia |
| 80121 | Car | Model A | Spare | 50125 | screw | Type A |
| 80121 | Car | Model A | Spare | 50126 | Shaft | 10m long |
| 80122 | Bike | Model H | Spare | 50127 | Oil | Standard oil |
+-------+-------+------------+------------+---------+-----------+----------------+
现在我必须在用户点击以下 URL 时提供以下响应,即对于 id 80121
http://localhost:8080/items?id=80121 。将有 2 个关系:Kits
和 Spare
。我想把所有的工具包都放在一个钥匙里,类似地备用在另一个钥匙里,如下所示。
{
"Id": "80121",
"Name": "Car",
"Desc": "Model A",
"Kits": [
{
"Id": "50123",
"Name": "Bolt",
"Desc": "Hexagonal Bolt"
},
{
"Id": "50124",
"Name": "Nut",
"Desc": "25mm Dia"
},
],
"Spare": [
{
"Id": "50125",
"Name": "screw",
"Desc": "Type A"
},
{
"Id": "50126",
"Name": "Shaft",
"Desc": "10m long"
},
]
}
类似地,当用户点击 http://localhost:8080/items?id=80112
{
"Id": "80112",
"Name": "Bike",
"Desc": "Model H",
"Kits": [],
"Spare": [
{
"Id": "50127",
"Name": "Oil",
"Desc": "Standard oil"
}
]
}
每个请求只有一个 ID。请帮助实现这一目标
下面我试过了
存储库
@Repository
public interface MyDataRepo extends JpaRepository<List, String> {
@Query(value="select ID,Name,Desc,Relation,ChildId,ChildName,ChildDesc from myview
WHERE ID=?1",nativeQuery=true)
List<Data> findAllCategory(String id);
public static interface Data {
String getid();
String getname();
String getdesc();
String getrelation();
String getchildid();
String getchildname();
String getchilddesc();
}
}
服务:
public List<Data> getMyData(String id) {
return repo.findAllCategory(id);
}
控制器:
@GetMapping("/items")
public ResponseEntity<List<Data>> retrieveData(@RequestParam("id") String id) {
List<Data> stud = service.getMyData(id);
return ResponseEntity.ok().body(stud);
}
80121
的当前输出:
[{
"Id": "80121",
"Name": "Car",
"Desc": "Model A",
"Relation":"Kits",
"ChildId":"50123",
"ChildName":"Bolt",
"ChildDesc":"Hexagonal Bolt"
}, {
"Id": "80121",
"Name": "Car",
"Desc": "Model A",
"Relation":"Kits",
"ChildId":"50124",
"ChildName":"Nut",
"ChildDesc":"25mm Dia"
}, {
"Id": "80121",
"Name": "Car",
"Desc": "Model A",
"Relation":"Spare",
"ChildId":"50125",
"ChildName":"screw",
"ChildDesc":"10m long "
}, {
"Id": "80121",
"Name": "Car",
"Desc": "Model A",
"Relation":"Spare",
"ChildId":"50126",
"ChildName":"Shaft",
"ChildDesc":"Pasted Seal"
}]
我是 Java 和 spring 引导的初学者。我应该创建一个带有视图列的自定义 POJO 或实体吗?我不知道如何创建这个嵌套的 JSON 并继续进行。如有任何指示,我们将不胜感激。
您这样做的方式是每行提供信息。解决它的一种方法是在返回控制之前开发一个序列化函数,例如 DTO。
另一种解决方案是正确映射实体并尝试执行相同的操作 select,这样它 returns 就如预期的那样
您应该声明三个独立的实体,如下所示。并在休息控制器中访问它们。
KitEntity
package com.example.demo;
import com.fasterxml.jackson.annotation.JsonIgnore;
import javax.persistence.*;
@Entity
public class KitEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) // automatic ID creation by hibernate.
private int id;
private String name;
private String desc;
@ManyToOne
@JoinColumn(name = "car_entity") // foreign key column which points to car table
@JsonIgnore
private CarEntity carEntity;
// getters and setters here
}
备用实体
package com.example.demo;
import com.fasterxml.jackson.annotation.JsonIgnore;
import javax.persistence.*;
@Entity
public class SpareEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
private String desc;
@ManyToOne
@JoinColumn(name = "car_entity") // foreign key column which points to car table
@JsonIgnore
private CarEntity carEntity;
// setters and getters here
}
汽车实体
@Entity
public class CarEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
@OneToMany(mappedBy = "carEntity") // here carEntity is a veriable name in KitEntity who have ManyToOne relation.
private List<KitEntity> kits;
@OneToMany(mappedBy = "carEntity") // here carEntity is a veriable name in SpareEntity who have ManyToOne relation.
private List<SpareEntity> spare;
// getters and setters here.
}
您可以使用 Spring Data JPA 的 JpaRepository 进行数据库访问。或者您可以使用休眠查询从该实体中获取数据。
此外,您还需要两个单独的实体来维护两个不同类型的列表,即备用和套件。您也可以使用枚举来定义类型,但这会很复杂,所以我不会那样做。
p.s。另请注意,您必须在套件和备用实体上使用 @JsonIgnore 以确保不会发生对 getter 的递归调用。
编辑:
car_entity 是您的套件和备用实体中的列名。
如果您想自己创建 tables,那么您应该在每个变量上使用 @Column 注释将其映射到数据库中的适当列。以及 class 级别的 @Table 并在该注释中提供您的 table 名称。
您需要在从数据库加载数据后对其进行处理。最简单的方法是按 Relation
列分组并将对象映射到 Map
实例。您可以将以下方法添加到您的服务层并在您的控制器中调用:
public Map<String, Object> getGroupedByRelationData(String id) {
List<Data> data = repo.findAllCategory(id)
if (data == null || data.isEmpty()) {
return Collections.emptyMap();
}
// from first objet on the list copy common properties
Data first = data.get(0);
Map<String, Object> result = new LinkedHashMap<>();
result.put("Id", first.getId());
result.put("Name", first.getName());
result.put("Desc", first.getDesc());
// group data by relation field
Map<String, List<Data>> grouped = data.stream().collect(Collectors.groupingBy(Data::getRelation));
// each entity convert to map with child values
grouped.forEach((k, v) -> {
result.put(k, v.stream().map(inputData -> {
Map<String, Object> childResult = new HashMap<>();
childResult.put("Id", inputData.getChildId());
childResult.put("Name", inputData.getChildName());
childResult.put("Desc", inputData.getChildDesc());
return childResult;
}).collect(Collectors.toList()));
});
return result;
}
当然,您需要更新控制器方法返回的类型。
我有一个 SQL 视图 (IdView
),它的值低于此值。我对此视图只有读取权限,对基础表没有任何访问权限。
+-------+-------+------------+------------+---------+-----------+----------------+
| ID | Name | Desc | Relation | ChildId | ChildName | ChildDesc |
+-------+-------+------------+------------+---------+-----------+----------------+
| 80121 | Car | Model A | Kits | 50123 | Bolt | Hexagonal Bolt |
| 80121 | Car | Model A | Kits | 50124 | Nut | 25mm Dia |
| 80121 | Car | Model A | Spare | 50125 | screw | Type A |
| 80121 | Car | Model A | Spare | 50126 | Shaft | 10m long |
| 80122 | Bike | Model H | Spare | 50127 | Oil | Standard oil |
+-------+-------+------------+------------+---------+-----------+----------------+
现在我必须在用户点击以下 URL 时提供以下响应,即对于 id 80121
http://localhost:8080/items?id=80121 。将有 2 个关系:Kits
和 Spare
。我想把所有的工具包都放在一个钥匙里,类似地备用在另一个钥匙里,如下所示。
{
"Id": "80121",
"Name": "Car",
"Desc": "Model A",
"Kits": [
{
"Id": "50123",
"Name": "Bolt",
"Desc": "Hexagonal Bolt"
},
{
"Id": "50124",
"Name": "Nut",
"Desc": "25mm Dia"
},
],
"Spare": [
{
"Id": "50125",
"Name": "screw",
"Desc": "Type A"
},
{
"Id": "50126",
"Name": "Shaft",
"Desc": "10m long"
},
]
}
类似地,当用户点击 http://localhost:8080/items?id=80112
{
"Id": "80112",
"Name": "Bike",
"Desc": "Model H",
"Kits": [],
"Spare": [
{
"Id": "50127",
"Name": "Oil",
"Desc": "Standard oil"
}
]
}
每个请求只有一个 ID。请帮助实现这一目标
下面我试过了
存储库
@Repository
public interface MyDataRepo extends JpaRepository<List, String> {
@Query(value="select ID,Name,Desc,Relation,ChildId,ChildName,ChildDesc from myview
WHERE ID=?1",nativeQuery=true)
List<Data> findAllCategory(String id);
public static interface Data {
String getid();
String getname();
String getdesc();
String getrelation();
String getchildid();
String getchildname();
String getchilddesc();
}
}
服务:
public List<Data> getMyData(String id) {
return repo.findAllCategory(id);
}
控制器:
@GetMapping("/items")
public ResponseEntity<List<Data>> retrieveData(@RequestParam("id") String id) {
List<Data> stud = service.getMyData(id);
return ResponseEntity.ok().body(stud);
}
80121
的当前输出:
[{
"Id": "80121",
"Name": "Car",
"Desc": "Model A",
"Relation":"Kits",
"ChildId":"50123",
"ChildName":"Bolt",
"ChildDesc":"Hexagonal Bolt"
}, {
"Id": "80121",
"Name": "Car",
"Desc": "Model A",
"Relation":"Kits",
"ChildId":"50124",
"ChildName":"Nut",
"ChildDesc":"25mm Dia"
}, {
"Id": "80121",
"Name": "Car",
"Desc": "Model A",
"Relation":"Spare",
"ChildId":"50125",
"ChildName":"screw",
"ChildDesc":"10m long "
}, {
"Id": "80121",
"Name": "Car",
"Desc": "Model A",
"Relation":"Spare",
"ChildId":"50126",
"ChildName":"Shaft",
"ChildDesc":"Pasted Seal"
}]
我是 Java 和 spring 引导的初学者。我应该创建一个带有视图列的自定义 POJO 或实体吗?我不知道如何创建这个嵌套的 JSON 并继续进行。如有任何指示,我们将不胜感激。
您这样做的方式是每行提供信息。解决它的一种方法是在返回控制之前开发一个序列化函数,例如 DTO。
另一种解决方案是正确映射实体并尝试执行相同的操作 select,这样它 returns 就如预期的那样
您应该声明三个独立的实体,如下所示。并在休息控制器中访问它们。
KitEntity
package com.example.demo;
import com.fasterxml.jackson.annotation.JsonIgnore;
import javax.persistence.*;
@Entity
public class KitEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) // automatic ID creation by hibernate.
private int id;
private String name;
private String desc;
@ManyToOne
@JoinColumn(name = "car_entity") // foreign key column which points to car table
@JsonIgnore
private CarEntity carEntity;
// getters and setters here
}
备用实体
package com.example.demo;
import com.fasterxml.jackson.annotation.JsonIgnore;
import javax.persistence.*;
@Entity
public class SpareEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
private String desc;
@ManyToOne
@JoinColumn(name = "car_entity") // foreign key column which points to car table
@JsonIgnore
private CarEntity carEntity;
// setters and getters here
}
汽车实体
@Entity
public class CarEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
@OneToMany(mappedBy = "carEntity") // here carEntity is a veriable name in KitEntity who have ManyToOne relation.
private List<KitEntity> kits;
@OneToMany(mappedBy = "carEntity") // here carEntity is a veriable name in SpareEntity who have ManyToOne relation.
private List<SpareEntity> spare;
// getters and setters here.
}
您可以使用 Spring Data JPA 的 JpaRepository 进行数据库访问。或者您可以使用休眠查询从该实体中获取数据。
此外,您还需要两个单独的实体来维护两个不同类型的列表,即备用和套件。您也可以使用枚举来定义类型,但这会很复杂,所以我不会那样做。
p.s。另请注意,您必须在套件和备用实体上使用 @JsonIgnore 以确保不会发生对 getter 的递归调用。
编辑: car_entity 是您的套件和备用实体中的列名。 如果您想自己创建 tables,那么您应该在每个变量上使用 @Column 注释将其映射到数据库中的适当列。以及 class 级别的 @Table 并在该注释中提供您的 table 名称。
您需要在从数据库加载数据后对其进行处理。最简单的方法是按 Relation
列分组并将对象映射到 Map
实例。您可以将以下方法添加到您的服务层并在您的控制器中调用:
public Map<String, Object> getGroupedByRelationData(String id) {
List<Data> data = repo.findAllCategory(id)
if (data == null || data.isEmpty()) {
return Collections.emptyMap();
}
// from first objet on the list copy common properties
Data first = data.get(0);
Map<String, Object> result = new LinkedHashMap<>();
result.put("Id", first.getId());
result.put("Name", first.getName());
result.put("Desc", first.getDesc());
// group data by relation field
Map<String, List<Data>> grouped = data.stream().collect(Collectors.groupingBy(Data::getRelation));
// each entity convert to map with child values
grouped.forEach((k, v) -> {
result.put(k, v.stream().map(inputData -> {
Map<String, Object> childResult = new HashMap<>();
childResult.put("Id", inputData.getChildId());
childResult.put("Name", inputData.getChildName());
childResult.put("Desc", inputData.getChildDesc());
return childResult;
}).collect(Collectors.toList()));
});
return result;
}
当然,您需要更新控制器方法返回的类型。