Я изучал некоторые весенние mvc, веб-и тимелист материал в течение нескольких недель после нескольких лет в качестве внутреннего разработчика. До сих пор я использовал mkyong и baeldung с довольно высокой степенью успеха. Однако я пытаюсь изменить пример для обеспечения проверки на лету с использованием Ajax, но мне кажется, что я немного изобретаю колесо, что обычно является признаком того, что я что-то пропустил.
У меня есть форма, которая позволяет мне добавлять / удалять строки, но я хотел бы проверить поля при вводе на стороне сервера (я думаю, что это может быть дорого, но это скорее принцип вещь на данный момент). Поэтому я создал тип @ControllerAdvice для обработки исключений нарушения ограничений, который возвращает некоторую информацию для обработки в javascript (этот бит я еще не сделал), потому что я чувствую, что должен быть какой-то способ использовать BindingResult для достижения все это.
Желаемый результат - подсвечивание недопустимых полей при вводе данных, ie, если цена отрицательная или поле пустое.
Если я должен использовать другой вариант JS или что-то подобное, я стремлюсь учиться. Я думаю, что предоставил все соответствующие источники, но я рад добавить еще.
Модель:
public class Book {
private final long id;
@NotEmpty(message = "Please provide a name")
private String name;
@NotEmpty(message = "Please provide a author")
private String author;
@NotNull(message = "Please provide a price")
@DecimalMin("1.00")
private BigDecimal price;
//snip
}
Репо:
public class BookRepository {
private static AtomicLong id = new AtomicLong(0L);
private Map<Long, Book> bookMap;
@PostConstruct
public void doStuff() {
bookMap = new HashMap<>();
System.out.println("init");
save(new Book("A Guide to the Bodhisattva Way of Life", "Santideva", new BigDecimal("15.41")));
save(new Book("The Life-Changing Magic of Tidying Up", "Marie Kondo", new BigDecimal("9.69")));
save(new Book("Refactoring: Improving the Design of Existing Code", "Martin Fowler", new BigDecimal("47.99")));
}
public static Long getNextId() {
return id.incrementAndGet();
}
public List<Book> findAll() {
return new ArrayList<>(bookMap.values());
}
public Book save(Book newBook) {
bookMap.put(newBook.getId(), newBook);
return newBook;
}
public void addNew() {
Book b = new Book();
bookMap.put(b.getId(), b);
}
public Optional<Book> findById(Long id) {
return Optional.ofNullable(bookMap.get(id));
}
public void deleteById(Long id) {
bookMap.remove(id);
}
}
@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<List<ResponseType>> handle(ConstraintViolationException exception) {
//you will get all javax failed validation, can be more than one
//so you can return the set of error messages or just the first message
exception.getConstraintViolations().forEach(e -> System.out.println(e.getLeafBean() + " " + e.getMessage() + " " + e.getPropertyPath()));
List<ResponseType> responseTypes = new ArrayList<>();
for (ConstraintViolation<?> violation : exception.getConstraintViolations()) {
ResponseType apiError = new ResponseType();
String path = violation.getPropertyPath().toString();
String field = path.substring(1+path.lastIndexOf("."));
apiError.setClazz(violation.getLeafBean().toString());
apiError.setExplanation(violation.getMessage());
apiError.setField(field);
responseTypes.add(apiError);
}
return ResponseEntity.badRequest().body(responseTypes);
}
<body>
<div class="container">
<div class="tab-content mt-20">
<div id="home" class="tab-pane fade in active">
<div id="formDiv" th:replace="fragments/fragment.html :: generateBooks (${books})"></div>
</div>
</div>
</div>
</body>
<div th:fragment="generateBooks (books)" id="formDiv" class="container">
<form id="form" class="forms my-5" name='f' th:action="@{/}" method='post' th:object="${books}">
<!--/*@thymesVar id="book" type="com.validator.validationdemos.mkyong.model.Book"*/-->
<div class="form-row" th:each="book ,index : ${books}" th:id="${'book'+index.index}">
<div id="formRow" th:replace="fragments/fragment.html :: generateRow (${book})"></div>
</div>
<div class="form-row ">
<div class="form-group col-md-2 pull-right">
<input class="form-control btn btn-primary" type="submit" value="Submit"/>
</div>
<div class="form-group col-md-2 pull-right">
<button class="form-control btn btn-success" type="button" id="addButton">Add Row</button>
</div>
</div>
</form>
</div>
<!--/*@thymesVar id="book" type="com.validator.validationdemos.mkyong.model.Book"*/-->
<div th:fragment="generateRow (book)" th:id="${'formRow'+book.id}" class="container">
<div class="form-group col-md-6">
<input th:id="${'bookName'+book.id}"
class="name form-control" th:value="${book.name}"/>
</div>
<div class="form-group col-md-2">
<input th:id="${'bookAuthor'+book.id}"
class="author form-control bg-danger" th:value="${book.author}"/>
</div>
<div class="form-group col-md-2">
<input th:id="${'bookPrice'+book.id}"
class="price form-control" th:value="${book.price}"/>
</div>
<div class="form-group col-md-2">
<button type="button" class="deleteButton form-control btn btn-danger"
th:id="${'delete'+book.id}"
th:data-index="${book.id}">Remove
</button>
</div>
</div>
$(document).on("keyup", ".form-control", function () {
let row = this.parentElement.parentElement;
let id = $(".deleteButton", row).attr('data-index');
let name = $(".name", row).val();
let author = $(".author", row).val();
let price = $(".price", row).val();
let book = {id, name, author, price};
$.ajax({
type: "PATCH",
url: "/books/",
data: JSON.stringify(book),
contentType: "application/json",
success: function (data) {
console.log("SUCCESS : " + data);
},
error: function (e) {
console.log("FAILURE");
let error = JSON.parse(e.responseText);
for (let i = 0; i < error.length; i++) {
console.log(error[i].field)
}
}
}); }