2017-02-02 5 views
1

В моем весеннем/загрузки Java у меня есть набор методов обслуживания, например, как следующий одно:метод Spring обслуживания и проверки сложной логики/правила

@Override 
public Decision create(String name, String description, String url, String imageUrl, Decision parentDecision, Tenant tenant, User user) { 

    name = StringUtils.trimMultipleSpaces(name); 
    if (org.apache.commons.lang3.StringUtils.isEmpty(name)) { 
     throw new IllegalArgumentException("Decision name can't be blank"); 
    } 
    if (!org.apache.commons.lang3.StringUtils.isEmpty(url) && !urlValidator.isValid(url)) { 
     throw new IllegalArgumentException("Decision url is not valid"); 
    } 
    if (!org.apache.commons.lang3.StringUtils.isEmpty(imageUrl) && !urlValidator.isValid(imageUrl)) { 
     throw new IllegalArgumentException("Decision imageUrl is not valid"); 
    } 

    if (user == null) { 
     throw new IllegalArgumentException("User can't be empty"); 
    } 

    if (tenant != null) { 
     List<Tenant> userTenants = tenantDao.findTenantsForUser(user.getId()); 
     if (!userTenants.contains(tenant)) { 
      throw new IllegalArgumentException("User doesn't belong to this tenant"); 
     } 
    } 

    if (parentDecision != null) { 
     if (tenant == null) { 
      if (findFreeChildDecisionByName(parentDecision.getId(), name) != null) { 
       throw new EntityAlreadyExistsException("Parent decision already contains a child decision with a given name"); 
      } 
     } else { 
      if (findTenantedChildDecisionByName(parentDecision.getId(), name, tenant.getId()) != null) { 
       throw new EntityAlreadyExistsException("Parent decision already contains a child decision with a given name"); 
      } 
     } 

     Tenant parentDecisionTenant = tenantDao.findTenantForDecision(parentDecision.getId()); 
     if (parentDecisionTenant != null) { 
      if (tenant == null) { 
       throw new IllegalArgumentException("Public decision cannot be added as a child to tenanted parent decision"); 
      } 
      if (!parentDecisionTenant.equals(tenant)) { 
       throw new IllegalArgumentException("Decision cannot belong to tenant other than parent decision tenant"); 
      } 
     } else { 
      if (tenant != null) { 
       throw new IllegalArgumentException("Tenanted decision cannot be added as a child to public parent decision"); 
      } 
     } 

    } else { 
     if (tenant == null) { 
      if (findFreeRootDecisionByName(name) != null) { 
       throw new EntityAlreadyExistsException("Root decision with a given name already exists"); 
      } 
     } else { 
      if (findTenantedRootDecisionByName(name, tenant.getId()) != null) { 
       throw new EntityAlreadyExistsException("Root decision with a given name for this tenant already exists"); 
      } 
     } 
    } 

    Decision decision = createOrUpdate(new Decision(name, description, url, imageUrl, parentDecision, user, tenant)); 

    if (parentDecision != null) { 
     parentDecision.addChildDecision(decision); 
    } 

    criterionGroupDao.create(CriterionGroupDaoImpl.DEFAULT_CRITERION_GROUP_NAME, null, decision, user); 
    characteristicGroupDao.create(CharacteristicGroupDaoImpl.DEFAULT_CHARACTERISTIC_GROUP_NAME, null, decision, user); 

    return decision; 
} 

Как вы можете видеть, большинство из строки кода из этого метода заняты логикой проверки, и я продолжаю добавлять новые случаи проверки.

Я хочу реорганизовать этот метод и переместить логику проверки вне этого метода в более подходящих местах. Пожалуйста, предложите, как это можно сделать с помощью Spring framework.

+3

Используйте JSR-303 для большей части этого и, возможно, имеете собственный класс проверки, который проверяет составной логин. Например, ваши первые несколько проверок могут быть уменьшены до '@ NotEmpty'. – chrylis

ответ

2

Как упоминалось в комментариях к chrylis, вы можете достичь этой цели, используя проверку бобов JSR-303. Первый шаг заключается в создании класса, который содержит ваши входные параметры:

public class DecisionInput { 
    private String name; 
    private String description; 
    private String url; 
    private String imageUrl; 
    private Decision parentDecision; 
    private Tenant tenant; 
    private User user; 

    // Constructors, getters, setters, ... 
} 

После этого, вы можете начать добавлять аннотации проверки, например:

public class DecisionInput { 
    @NotEmpty 
    private String name; 
    @NotEmpty 
    private String description; 
    @NotEmpty 
    private String url; 
    @NotEmpty 
    private String imageUrl; 
    private Decision parentDecision; 
    private Tenant tenant; 
    @NotNull 
    private User user; 

    // Constructors, getters, setters, ... 
} 

Имейте в виду, что @NotEmpty аннотации а не стандартную аннотацию JSR-303, но аннотацию Hibernate. Если вы предпочитаете использовать стандартный JSR-303, вы всегда можете создать свой собственный валидатор. Для вашего арендатора и вашего решения вам определенно нужен специальный валидатор. Прежде всего создайте аннотацию (например, @ValidTenant). В своем классе аннотаций, убедитесь, чтобы добавить @Constraint аннотации, например:

@Constraint(validatedBy = TenantValidator.class) // Your validator class 
@Target({ TYPE, ANNOTATION_TYPE }) // Static import from ElementType, change this to METHOD/FIELD if you want to create a validator for a single field (rather than a cross-field validation) 
@Retention(RUNTIME) // Static import from RetentionPolicy 
@Documented 
public @interface ValidTenant { 
    String message() default "{ValidTenant.message}"; 
    Class<?>[] groups() default { }; 
    Class<? extends Payload>[] payload() default { }; 
} 

Теперь вы должны создать TenantValidator класс и сделать его реализацию ConstraintValidator<ValidTenant, DecisionInput>, например:

@Component 
public class TenantValidator implements ConstraintValidator<ValidTenant, DecisionInput> { 
    @Autowired 
    private TenantDAO tenantDao; 

    @Override 
    public void initialize(ValidTenant annotation) { 
    } 

    @Override 
    public boolean isValid(DecisionInput input, ConstraintValidatorContext context) { 
     List<Tenant> userTenants = tenantDao.findTenantsForUser(input.getUser().getId()); 
     return userTenants.contains(input.getTenant()); 
    } 
} 

То же самое можно для проверки родительского решения. Теперь вы можете просто реорганизовать метод обслуживания к этому:

public Decision create(@Valid DecisionInput input) { 
    // No more validation logic necessary 
} 

Если вы хотите использовать свои собственные сообщения об ошибках, я предлагаю читать this answer. В основном вы создаете файл ValidationMessages.properties и размещаете там свои сообщения.

+0

Спасибо за подробный ответ! Еще один вопрос - все ли вызовы проверки выполняются в той же транзакции, что и метод службы? – alexanoid

+1

@alexanoid Я не уверен на 100%, но насколько я знаю, аспекты выполняются в одном и том же контексте транзакций, поэтому я предполагаю, что логика проверки также будет выполняться в том же контексте. – g00glen00b

 Смежные вопросы

  • Нет связанных вопросов^_^