自动转换为多个域对象的集中式 bean
Convert automatically into a centralized bean for multiple domain objects
我正在创建一个项目,它将响应收集多个 bean 对象,将其保存到数据库和 return 事务的状态。客户端可以发送多个对象。对于每个对象,它们都有单独的数据库,因此有单独的控制器。
所以我打算创建一个框架,可以接受来自多个控制器的多个对象,并且只发送一个集中的对象。但是我不确定如何在控制器中将集中式对象用作 return 类型(目前我将它们 return 编辑为 Object
)。下面是我的代码:
控制器:
@RestController
@RequestMapping("/stat/player")
public class PlayerController {
@Autowired
private StatService<PlayerValue> statPlayer;
@RequestMapping("/number/{number}")
public Object findByNumber(@PathVariable String number) { // Here returning Object seem odd
return statPlayer.findByNumber(number);
}
}
服务:
@Service
@Transactional(isolation = Isolation.READ_COMMITTED)
public class PlayerServiceImpl implements StatService<PlayerValue> {
@Autowired
private PlayerRepository repository;
@Override
public PlayerValue findByNumber(String number) {
Optional<PlayerEntity> numberValue = repository.findByNumber(number);
return numberValue.map(PlayerEntity::toValue).orElse(null);
}
}
在服务中,我 return 编辑了 PlayerValue
对象,但我想将此对象包装到一个集中的 bean ResponseValue 中。我为此创建了一个方面
@Aspect
@Component
public class Converter {
private static final Logger LOG = LoggerFactory.getLogger(Converter.class);
@Pointcut("within(@org.springframework.web.bind.annotation.RestController *)")
public void restControllerClassMethod() {}
private <T> ResponseValue<T> convert(List<T> results) {
String message = results.isEmpty() ? "No result found" : ResponseValueStatus.OK.toString();
return new ResponseValue<>(ResponseValueStatus.OK, message, results);
}
@Around("restControllerClassMethod()")
@SuppressWarnings("unchecked")
public <T> ResponseValue<T> convert(ProceedingJoinPoint joinPoint) {
ResponseValue value;
try {
Object findObject = joinPoint.proceed();
List<Object> objects = toList(findObject);
value = convert(objects);
} catch (NullPointerException e) {
throw new StatException(String.format("Exception thrown from %s from %s method with parameter %s", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName(), joinPoint.getArgs()[0].toString()));
//this exception will go in a controller advice and create a response value with this message
} catch (Throwable e) {
LOG.error("Exception occurred while converting the object", e);
throw new StatException(String.format("Exception thrown from %s from %s method with parameter %s with exception message %s", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName(), joinPoint.getArgs()[0].toString(), e.getMessage()));
}
return value;
}
private List<Object> toList(Object findObject) {
List<Object> objects = new ArrayList<>();
if (findObject instanceof List) {
((List) findObject).forEach(item -> objects.add(findObject));
} else {
objects.add(findObject);
}
return objects;
}
}
综上所述,可能存在多个类似于PlayerValue的实体。我需要一种方法来 return 集中 bean 中的结果。以上流程工作,但为此我必须在 Controller
中将 return 类型设为 Object
。有没有人知道如何在控制器中使用 return 类型作为列表或 T。我也知道可以通过实现 ValueConverter
接口来完成,但这种转换很简单。因此,如果任何其他开发人员不必在每次他想添加不同的控制器时都实施 ValueConverter
就好了。
也可以随时查看实施情况,如果有人有其他想法或意见,请告诉我。
注意:我在题中减少了很多代码,这样可以在不了解实际需求上下文的情况下更容易理解。如果有人需要更多信息,请告诉我。
如果您创建一个通用的 AbstractStatController
会怎么样?
通用接口StatService
:
public interface StatService<T> {
T findByNumber(String number);
}
通用摘要 class AbstractStatController
:
public abstract class AbstractStatController<T> {
abstract StatService<T> getStatService();
@RequestMapping("/number/{number}")
public T findByNumber(@PathVariable String number) {
return getStatService().findByNumber(number);
}
}
混凝土classPlayerController
:
@RestController
@RequestMapping("/stat/player")
public class PlayerController extends AbstractStatController<Player> {
private final PlayerService playerService;
public PlayerController(PlayerService playerService) {
this.playerService = playerService;
}
@Override
StatService<Player> getStatService() {
return playerService;
}
}
经过一些研究,我发现一个更好的框架设计解决方案(但当然有缺陷)来实现向多个域对象的集中式 bean 的转换是使用标记接口。
标记接口可以为所有的bean提供一个集中类型。客户端需要遵循的主要规则是实现该标记接口。所以基本的解决方案是
标记界面:
public interface StateResponseValue<T> {
}
在所有bean中实现接口。
public class PlayerValue implements StateResponseValue<PlayerValue> {
}
public class ResponseValue<T> implements StateResponseValue<T> {
//fields and their getter and setter
}
更改服务和控制器中的 return 类型。
public interface StatService<T> {
StateResponseValue<T> findByNumber(String number);
}
更改控制器中的 return 类型
@RestController
@RequestMapping("/stat/player")
public class PlayerController {
@Autowired
private StatService<PlayerValue> statPlayer;
@RequestMapping("/number/{number}")
public StateResponseValue<T> findByNumber(@PathVariable String number) { // Here returning Object seem odd
return statPlayer.findByNumber(number);
}
}
注意: 我觉得主要的缺点是无论何时我们想要访问字段客户端都需要显式地将对象转换为 ResponseValue
,这仍然很丑陋。
我正在创建一个项目,它将响应收集多个 bean 对象,将其保存到数据库和 return 事务的状态。客户端可以发送多个对象。对于每个对象,它们都有单独的数据库,因此有单独的控制器。
所以我打算创建一个框架,可以接受来自多个控制器的多个对象,并且只发送一个集中的对象。但是我不确定如何在控制器中将集中式对象用作 return 类型(目前我将它们 return 编辑为 Object
)。下面是我的代码:
控制器:
@RestController
@RequestMapping("/stat/player")
public class PlayerController {
@Autowired
private StatService<PlayerValue> statPlayer;
@RequestMapping("/number/{number}")
public Object findByNumber(@PathVariable String number) { // Here returning Object seem odd
return statPlayer.findByNumber(number);
}
}
服务:
@Service
@Transactional(isolation = Isolation.READ_COMMITTED)
public class PlayerServiceImpl implements StatService<PlayerValue> {
@Autowired
private PlayerRepository repository;
@Override
public PlayerValue findByNumber(String number) {
Optional<PlayerEntity> numberValue = repository.findByNumber(number);
return numberValue.map(PlayerEntity::toValue).orElse(null);
}
}
在服务中,我 return 编辑了 PlayerValue
对象,但我想将此对象包装到一个集中的 bean ResponseValue 中。我为此创建了一个方面
@Aspect
@Component
public class Converter {
private static final Logger LOG = LoggerFactory.getLogger(Converter.class);
@Pointcut("within(@org.springframework.web.bind.annotation.RestController *)")
public void restControllerClassMethod() {}
private <T> ResponseValue<T> convert(List<T> results) {
String message = results.isEmpty() ? "No result found" : ResponseValueStatus.OK.toString();
return new ResponseValue<>(ResponseValueStatus.OK, message, results);
}
@Around("restControllerClassMethod()")
@SuppressWarnings("unchecked")
public <T> ResponseValue<T> convert(ProceedingJoinPoint joinPoint) {
ResponseValue value;
try {
Object findObject = joinPoint.proceed();
List<Object> objects = toList(findObject);
value = convert(objects);
} catch (NullPointerException e) {
throw new StatException(String.format("Exception thrown from %s from %s method with parameter %s", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName(), joinPoint.getArgs()[0].toString()));
//this exception will go in a controller advice and create a response value with this message
} catch (Throwable e) {
LOG.error("Exception occurred while converting the object", e);
throw new StatException(String.format("Exception thrown from %s from %s method with parameter %s with exception message %s", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName(), joinPoint.getArgs()[0].toString(), e.getMessage()));
}
return value;
}
private List<Object> toList(Object findObject) {
List<Object> objects = new ArrayList<>();
if (findObject instanceof List) {
((List) findObject).forEach(item -> objects.add(findObject));
} else {
objects.add(findObject);
}
return objects;
}
}
综上所述,可能存在多个类似于PlayerValue的实体。我需要一种方法来 return 集中 bean 中的结果。以上流程工作,但为此我必须在 Controller
中将 return 类型设为 Object
。有没有人知道如何在控制器中使用 return 类型作为列表或 T。我也知道可以通过实现 ValueConverter
接口来完成,但这种转换很简单。因此,如果任何其他开发人员不必在每次他想添加不同的控制器时都实施 ValueConverter
就好了。
也可以随时查看实施情况,如果有人有其他想法或意见,请告诉我。
注意:我在题中减少了很多代码,这样可以在不了解实际需求上下文的情况下更容易理解。如果有人需要更多信息,请告诉我。
如果您创建一个通用的 AbstractStatController
会怎么样?
通用接口StatService
:
public interface StatService<T> {
T findByNumber(String number);
}
通用摘要 class AbstractStatController
:
public abstract class AbstractStatController<T> {
abstract StatService<T> getStatService();
@RequestMapping("/number/{number}")
public T findByNumber(@PathVariable String number) {
return getStatService().findByNumber(number);
}
}
混凝土classPlayerController
:
@RestController
@RequestMapping("/stat/player")
public class PlayerController extends AbstractStatController<Player> {
private final PlayerService playerService;
public PlayerController(PlayerService playerService) {
this.playerService = playerService;
}
@Override
StatService<Player> getStatService() {
return playerService;
}
}
经过一些研究,我发现一个更好的框架设计解决方案(但当然有缺陷)来实现向多个域对象的集中式 bean 的转换是使用标记接口。
标记接口可以为所有的bean提供一个集中类型。客户端需要遵循的主要规则是实现该标记接口。所以基本的解决方案是
标记界面:
public interface StateResponseValue<T> {
}
在所有bean中实现接口。
public class PlayerValue implements StateResponseValue<PlayerValue> {
}
public class ResponseValue<T> implements StateResponseValue<T> {
//fields and their getter and setter
}
更改服务和控制器中的 return 类型。
public interface StatService<T> {
StateResponseValue<T> findByNumber(String number);
}
更改控制器中的 return 类型
@RestController
@RequestMapping("/stat/player")
public class PlayerController {
@Autowired
private StatService<PlayerValue> statPlayer;
@RequestMapping("/number/{number}")
public StateResponseValue<T> findByNumber(@PathVariable String number) { // Here returning Object seem odd
return statPlayer.findByNumber(number);
}
}
注意: 我觉得主要的缺点是无论何时我们想要访问字段客户端都需要显式地将对象转换为 ResponseValue
,这仍然很丑陋。