河南商务网站建设,wex5网站开发,网页设计好看的网站,进入这个网站java 错误输入异常在我以前的文章中#xff0c;我写了一篇关于输入验证设计的文章 #xff0c;该设计取代了难以维护和测试的 if-else块。 但是#xff0c;正如某些读者指出的那样#xff0c;它有一个缺点–如果输入数据有多个验证错误#xff0c;则用户将不得不多次提交请… java 错误输入异常 在我以前的文章中我写了一篇关于输入验证设计的文章 该设计取代了难以维护和测试的 if-else块。 但是正如某些读者指出的那样它有一个缺点–如果输入数据有多个验证错误则用户将不得不多次提交请求才能找到所有请求。 从可用性的角度来看这不是一个好的设计。 当我们发现验证错误时抛出异常的另一种方法是返回一个包含错误的Notification对象。 这将使我们能够在用户输入上运行所有验证规则并同时捕获所有违规行为。 Martin Fowler 撰写了一篇文章详细介绍了该方法。 我强烈建议您继续阅读如果您还没有读过的话。 在本文中我将重构以前的实现以使用错误通知对象来验证用户输入。 第一步我将创建一个ErrorNotification对象该对象封装了我的应用程序错误- public class ErrorNotification {private ListString errors new ArrayList();public void addError(String message) {this.errors.add(message);}public boolean hasError() {return !this.errors.isEmpty();}public String getAllErrors() {return this.errors.stream().collect(joining(, ));}
} 然后我将更改OrderItemValidator接口以返回ErrorNotification对象– public interface OrderItemValidator {ErrorNotification validate(OrderItem orderItem);
} 然后更改所有实现以适应新的返回类型。 最初我将更改所有实现以返回一个空的错误对象以便摆脱编译错误。 例如我将通过以下方式更改ItemDescriptionValidator – class ItemDescriptionValidator implements OrderItemValidator {Overridepublic ErrorNotification validate(OrderItem orderItem) {ErrorNotification errorNotification new ErrorNotification();Optional.ofNullable(orderItem).map(OrderItem::getDescription).map(String::trim).filter(description - !description.isEmpty()).orElseThrow(() - new IllegalArgumentException(Item description should be provided));return errorNotification;}
} 修复编译错误之后我现在将开始使用每个验证器中的通知消息替换异常。 为此我将首先修改相关测试以反映我的意图然后修改验证器以通过测试。 让我们从ItemDescriptionValidatorTest类开始– public class ItemDescriptionValidatorTest {Testpublic void validate_descriptionIsNull_invalid() {ItemDescriptionValidator validator new ItemDescriptionValidator();ErrorNotification errorNotification validator.validate(new OrderItem());assertThat(errorNotification.getAllErrors()).isEqualTo(Item description should be provided);}Testpublic void validate_descriptionIsBlank_invalid() {OrderItem orderItem new OrderItem();orderItem.setDescription( );ItemDescriptionValidator validator new ItemDescriptionValidator();ErrorNotification errorNotification validator.validate(new OrderItem());assertThat(errorNotification.getAllErrors()).isEqualTo(Item description should be provided);}Testpublic void validate_descriptionGiven_valid() {OrderItem orderItem new OrderItem();orderItem.setDescription(dummy description);ItemDescriptionValidator validator new ItemDescriptionValidator();ErrorNotification errorNotification validator.validate(orderItem);assertThat(errorNotification.getAllErrors()).isEmpty();}
} 当我运行这些测试时只有其中一项通过而其中两项失败这是预料之中的。 我现在将修改验证器代码以通过测试– class ItemDescriptionValidator implements OrderItemValidator {static final String MISSING_ITEM_DESCRIPTION Item description should be provided;Overridepublic ErrorNotification validate(OrderItem orderItem) {ErrorNotification errorNotification new ErrorNotification();Optional.ofNullable(orderItem).map(OrderItem::getDescription).map(String::trim).filter(description - !description.isEmpty()).ifPresentOrElse(description - {},() - errorNotification.addError(MISSING_ITEM_DESCRIPTION));return errorNotification;}
} 我对上面的ifPresentOrElse方法的使用感到不舒服。 我在这里使用它的主要原因是因为Optionals没有ifNotPresent方法之类的东西它将使我仅在不存在该值的情况下才采取措施请向读者提出要求-如果您知道一种更好的方法为此请发表评论。 进行此重构后 ItemValidatorTest类中的所有测试均通过测试。 大 现在让我们重构MenuValidatorTest类中的测试– public class MenuValidatorTest {Testpublic void validate_menuIdInvalid_invalid() {OrderItem orderItem new OrderItem();String menuId some menu id;orderItem.setMenuId(menuId);MenuRepository menuRepository mock(MenuRepository.class);when(menuRepository.menuExists(any())).thenReturn(false);MenuValidator validator new MenuValidator(menuRepository);ErrorNotification errorNotification validator.validate(orderItem);assertThat(errorNotification.getAllErrors()).isEqualTo(String.format(MenuValidator.INVALID_MENU_ERROR_FORMAT, menuId));}Testpublic void validate_menuIdNull_invalid() {MenuRepository menuRepository mock(MenuRepository.class);when(menuRepository.menuExists(any())).thenReturn(true);MenuValidator validator new MenuValidator(menuRepository);ErrorNotification errorNotification validator.validate(new OrderItem());assertThat(errorNotification.getAllErrors()).isEqualTo(MenuValidator.MISSING_MENU_ERROR);}Testpublic void validate_menuIdIsBlank_invalid() {OrderItem orderItem new OrderItem();orderItem.setMenuId( \t);MenuRepository menuRepository mock(MenuRepository.class);when(menuRepository.menuExists(any())).thenReturn(true);MenuValidator validator new MenuValidator(menuRepository);ErrorNotification errorNotification validator.validate(orderItem);assertThat(errorNotification.getAllErrors()).isEqualTo(MenuValidator.MISSING_MENU_ERROR);}Testpublic void validate_menuIdValid_validated() {OrderItem orderItem new OrderItem();String menuId some menu id;orderItem.setMenuId(menuId);MenuRepository menuRepository mock(MenuRepository.class);when(menuRepository.menuExists(menuId)).thenReturn(true);MenuValidator validator new MenuValidator(menuRepository);ErrorNotification errorNotification validator.validate(orderItem);assertThat(errorNotification.getAllErrors()).isEmpty();}
} 然后是MenuValidator类– RequiredArgsConstructor
class MenuValidator implements OrderItemValidator {private final MenuRepository menuRepository;static final String MISSING_MENU_ERROR A menu item must be specified.;static final String INVALID_MENU_ERROR_FORMAT Given menu [%s] does not exist.;Overridepublic ErrorNotification validate(OrderItem orderItem) {ErrorNotification errorNotification new ErrorNotification();Optional.ofNullable(orderItem.getMenuId()).map(String::trim).filter(menuId - !menuId.isEmpty()).ifPresentOrElse(validateMenuExists(errorNotification),() - errorNotification.addError(MISSING_MENU_ERROR));return errorNotification;}private ConsumerString validateMenuExists(ErrorNotification errorNotification) {return menuId - {if (!menuRepository.menuExists(menuId)) {errorNotification.addError(String.format(INVALID_MENU_ERROR_FORMAT, menuId));}};}
} 等等。 修改了各个验证器后我现在将修改Composite以收集单个订单商品的所有错误– RequiredArgsConstructor
class OrderItemValidatorComposite implements OrderItemValidator {private final ListOrderItemValidator validators;Overridepublic ErrorNotification validate(OrderItem orderItem) {ErrorNotification errorNotification new ErrorNotification();validators.stream().map(validator - validator.validate(orderItem)).forEach(errorNotification::addAll);return errorNotification;}
} 为此我在ErrorNotification类中添加了一个名为addAll的新方法该方法基本上从另一个ErrorNotification对象复制所有错误。 最后我现在将修改服务方法以收集订单中所有订单项的所有错误消息– Service
Slf4j
RequiredArgsConstructor
class OrderService {private final OrderItemValidator validator;void createOrder(OrderDTO orderDTO) {ErrorNotification errorNotification new ErrorNotification();orderDTO.getOrderItems().stream().map(validator::validate).forEach(errorNotification::addAll);if (errorNotification.hasError()) {throw new IllegalArgumentException(errorNotification.getAllErrors());}log.info(Order {} saved, orderDTO);}
} 进行此更改会导致OrderServiceIT中的测试之一失败因为它特别是在价格无效时寻找原因设置为NumberFormatException的异常。 重构之后我们可以安全地删除此检查因为它不再相关。 本文的完整源代码已推送到GitHub 特定的提交URL在此处 。 翻译自: https://www.javacodegeeks.com/2017/11/replacing-exceptions-error-notifications-input-validation-java.htmljava 错误输入异常