代码之家  ›  专栏  ›  技术社区  ›  Deb

自动转换为多个域对象的集中bean

  •  11
  • Deb  · 技术社区  · 6 年前

    我正在创建一个项目,该项目将响应收集多个bean对象,将其保存到数据库并返回事务的状态。可以从客户端发送多个对象。对于每个对象,它们都有独立的数据库,因此独立的控制器。

    所以我计划创建一个框架,它可以接受来自多个控制器的多个对象,并且只发送一个集中的对象。但我不知道如何在控制器中使用集中式对象作为返回类型(目前我返回它们为 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);
        }
    }
    

    在服役期间,我把 PlayerValue 但我想将这个对象包装成一个集中的bean响应值。我为此创造了一个方面

    @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的实体。我需要一种将结果返回到集中bean中的方法。以上流程工作,但为此,我必须给出返回类型 对象 在里面 Controller . 有人知道如何在控制器中使用返回类型作为list或t吗?我也知道它可以通过实现 ValueConverter 接口,但是这个转换很简单。因此,如果其他开发人员不必实现 价值转换器 每次他想添加不同的控制器。

    还可以随时查看实现,并告诉我是否有人有其他想法或意见。

    注: 我减少了问题中的大量代码,以便在不理解实际需求上下文的情况下更容易理解。如果有人需要更多信息,请告诉我。

    2 回复  |  直到 6 年前
        1
  •  3
  •   Deb    6 年前

    经过一些研究,我发现了一个更好的框架设计解决方案(当然是有缺陷的),为了实现多个域对象向集中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
    }
    

    更改服务和控制器中的返回类型。

    public interface StatService<T> {
        StateResponseValue<T> findByNumber(String number);
    }
    

    更改控制器中的返回类型

    @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 这仍然很难看。

        2
  •  0
  •   chubock    6 年前

    如果你创建一个 AbstractStatController 哪个是通用的?

    通用接口 StatService :

    public interface StatService<T> {
        T findByNumber(String number);
    }
    

    泛型抽象类 抽象控制器 :

    public abstract class AbstractStatController<T> {
    
        abstract StatService<T> getStatService();
    
        @RequestMapping("/number/{number}")
        public T findByNumber(@PathVariable String number) {
            return getStatService().findByNumber(number);
        }
    
    }
    

    混凝土等级 PlayerController :

    @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;
        }
    }