mirror of
https://github.com/dalbodeule/snap-admin.git
synced 2025-06-08 21:38:21 +00:00
JPA Validation WIP
This commit is contained in:
parent
4b21437c30
commit
2fb76d445f
@ -33,6 +33,7 @@ import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.jdbc.UncategorizedSQLException;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.transaction.TransactionSystemException;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
@ -476,6 +477,20 @@ public class DefaultDbAdminController {
|
||||
attr.addFlashAttribute("error", "See below for details");
|
||||
attr.addFlashAttribute("validationErrors", new ValidationErrorsContainer(e));
|
||||
attr.addFlashAttribute("params", params);
|
||||
} catch (DbAdminException e) {
|
||||
attr.addFlashAttribute("errorTitle", "Error");
|
||||
attr.addFlashAttribute("error", e.getMessage());
|
||||
attr.addFlashAttribute("params", params);
|
||||
} catch (TransactionSystemException e) {
|
||||
if (e.getRootCause() instanceof ConstraintViolationException) {
|
||||
ConstraintViolationException ee = (ConstraintViolationException)e.getRootCause();
|
||||
attr.addFlashAttribute("errorTitle", "Validation error");
|
||||
attr.addFlashAttribute("error", "See below for details");
|
||||
attr.addFlashAttribute("validationErrors", new ValidationErrorsContainer(ee));
|
||||
attr.addFlashAttribute("params", params);
|
||||
} else {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -89,7 +89,7 @@ public class CustomJpaRepository extends SimpleJpaRepository {
|
||||
.where(
|
||||
cb.or(
|
||||
cb.and(finalPredicates.toArray(new Predicate[finalPredicates.size()])), // query search on String fields
|
||||
cb.equal(root.get(schema.getPrimaryKey().getName()), q)
|
||||
cb.equal(root.get(schema.getPrimaryKey().getName()).as(String.class), q)
|
||||
)
|
||||
|
||||
);
|
||||
|
@ -19,9 +19,7 @@
|
||||
|
||||
package tech.ailef.dbadmin.external.dbmapping;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
@ -34,7 +32,6 @@ import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
@ -216,43 +213,47 @@ public class DbAdminRepository {
|
||||
@Transactional("transactionManager")
|
||||
public Object create(DbObjectSchema schema, Map<String, String> values, Map<String, MultipartFile> files, String primaryKey) {
|
||||
DbObject obj = schema.buildObject(values, files);
|
||||
|
||||
Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
|
||||
Set<ConstraintViolation<Object>> violations = validator.validate(obj.getUnderlyingInstance());
|
||||
|
||||
if (violations.size() > 0) {
|
||||
throw new ConstraintViolationException(violations);
|
||||
}
|
||||
|
||||
SimpleJdbcInsert insert = new SimpleJdbcInsert(jdbcTemplate).withTableName(schema.getTableName());
|
||||
|
||||
Map<String, Object> allValues = new HashMap<>();
|
||||
allValues.putAll(values);
|
||||
|
||||
values.keySet().forEach(fieldName -> {
|
||||
if (values.get(fieldName).isBlank()) {
|
||||
allValues.put(fieldName, null);
|
||||
}
|
||||
});
|
||||
|
||||
files.keySet().forEach(f -> {
|
||||
try {
|
||||
// The file parameter gets sent even if empty, so it's needed
|
||||
// to check if the file has actual content, to avoid storing an empty file
|
||||
if (files.get(f).getSize() > 0)
|
||||
allValues.put(f, files.get(f).getBytes());
|
||||
} catch (IOException e) {
|
||||
throw new DbAdminException(e);
|
||||
}
|
||||
});
|
||||
|
||||
if (primaryKey == null) {
|
||||
insert = insert.usingGeneratedKeyColumns(schema.getPrimaryKey().getName());
|
||||
return insert.executeAndReturnKey(allValues);
|
||||
} else {
|
||||
insert.execute(allValues);
|
||||
return primaryKey;
|
||||
}
|
||||
Object save = save(schema, obj);
|
||||
return new DbObject(save, schema).getPrimaryKeyValue();
|
||||
// return save;
|
||||
// System.out.println(obj);
|
||||
// Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
|
||||
// validator.va
|
||||
// Set<ConstraintViolation<Object>> violations = validator.validate(obj.getUnderlyingInstance());
|
||||
//
|
||||
// if (violations.size() > 0) {
|
||||
// throw new ConstraintViolationException(violations);
|
||||
// }
|
||||
//
|
||||
// SimpleJdbcInsert insert = new SimpleJdbcInsert(jdbcTemplate).withTableName(schema.getTableName());
|
||||
//
|
||||
// Map<String, Object> allValues = new HashMap<>();
|
||||
// allValues.putAll(values);
|
||||
//
|
||||
// values.keySet().forEach(fieldName -> {
|
||||
// if (values.get(fieldName).isBlank()) {
|
||||
// allValues.put(fieldName, null);
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// files.keySet().forEach(f -> {
|
||||
// try {
|
||||
// // The file parameter gets sent even if empty, so it's needed
|
||||
// // to check if the file has actual content, to avoid storing an empty file
|
||||
// if (files.get(f).getSize() > 0)
|
||||
// allValues.put(f, files.get(f).getBytes());
|
||||
// } catch (IOException e) {
|
||||
// throw new DbAdminException(e);
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// if (primaryKey == null) {
|
||||
// insert = insert.usingGeneratedKeyColumns(schema.getPrimaryKey().getName());
|
||||
// return insert.executeAndReturnKey(allValues);
|
||||
// } else {
|
||||
// insert.execute(allValues);
|
||||
// return primaryKey;
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
|
@ -27,6 +27,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.ManyToMany;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.OneToMany;
|
||||
@ -208,6 +209,12 @@ public class DbField {
|
||||
return getPrimitiveField().getAnnotation(ReadOnly.class) != null;
|
||||
}
|
||||
|
||||
public boolean isToOne() {
|
||||
return (getPrimitiveField().getAnnotation(OneToOne.class) != null &&
|
||||
getPrimitiveField().getAnnotation(OneToOne.class).mappedBy().isBlank())
|
||||
|| getPrimitiveField().getAnnotation(ManyToOne.class) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if this field is settable with a raw value, i.e.
|
||||
* a field that is not a relationship to another entity;
|
||||
@ -220,6 +227,10 @@ public class DbField {
|
||||
&& getPrimitiveField().getAnnotation(ManyToMany.class) == null;
|
||||
}
|
||||
|
||||
public boolean isGeneratedValue() {
|
||||
return getPrimitiveField().getAnnotation(GeneratedValue.class) != null;
|
||||
}
|
||||
|
||||
public Set<DbFieldValue> getAllValues() {
|
||||
List<?> findAll = schema.getJpaRepository().findAll();
|
||||
return findAll.stream()
|
||||
|
@ -32,7 +32,6 @@ import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.OneToOne;
|
||||
import tech.ailef.dbadmin.external.annotations.DisplayName;
|
||||
import tech.ailef.dbadmin.external.exceptions.DbAdminException;
|
||||
import tech.ailef.dbadmin.external.misc.Utils;
|
||||
|
||||
/**
|
||||
* Wrapper for all objects retrieved from the database.
|
||||
@ -183,6 +182,29 @@ public class DbObject {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setRelationship(String fieldName, Object primaryKeyValue) {
|
||||
DbField field = schema.getFieldByName(fieldName);
|
||||
DbObjectSchema linkedSchema = field.getConnectedSchema();
|
||||
Optional<?> obj = linkedSchema.getJpaRepository().findById(primaryKeyValue);
|
||||
|
||||
if (!obj.isPresent()) {
|
||||
throw new DbAdminException("Invalid value " + primaryKeyValue + " for " + fieldName
|
||||
+ ": item does not exist.");
|
||||
}
|
||||
|
||||
Method setter = findSetter(field.getJavaName());
|
||||
|
||||
if (setter == null) {
|
||||
throw new DbAdminException("Unable to find setter method for " + fieldName + " in " + schema.getClassName());
|
||||
}
|
||||
|
||||
try {
|
||||
setter.invoke(instance, obj.get());
|
||||
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
|
||||
}
|
||||
}
|
||||
|
||||
public void set(String fieldName, Object value) {
|
||||
Method setter = findSetter(fieldName);
|
||||
|
||||
@ -229,4 +251,11 @@ public class DbObject {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DbObject [instance=" + instance + ", schema=" + schema + "]";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -384,6 +384,10 @@ public class DbObjectSchema {
|
||||
if (parsedFieldValue != null && getFieldByName(param).isSettable()) {
|
||||
setter.invoke(instance, parsedFieldValue);
|
||||
}
|
||||
|
||||
if (parsedFieldValue != null && getFieldByName(param).isToOne()) {
|
||||
dbObject.setRelationship(param, parsedFieldValue);
|
||||
}
|
||||
}
|
||||
|
||||
for (String fileParam : files.keySet()) {
|
||||
|
@ -29,4 +29,11 @@ public class ValidationErrorsContainer {
|
||||
public boolean isEmpty() {
|
||||
return errors.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ValidationErrorsContainer [errors=" + errors + "]";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -31,6 +31,7 @@
|
||||
<form class="form" enctype="multipart/form-data" method="post" th:action="|/${dbadmin_baseUrl}/model/${className}/create|">
|
||||
<input type="hidden" name="__dbadmin_create" th:value="${create}">
|
||||
<div th:each="field : ${schema.getSortedFields(false)}" class="mt-2"
|
||||
th:if="${!field.isGeneratedValue() || !create}"
|
||||
th:classAppend="|${validationErrors != null && validationErrors.hasErrors(field.getJavaName()) ? 'invalid' : ''}|">
|
||||
<label th:for="|__id_${field.getName()}|" class="mb-1 fw-bold">
|
||||
<span th:if="${!field.isNullable() && !field.isPrimaryKey()}">
|
||||
|
@ -68,7 +68,7 @@
|
||||
<td>
|
||||
<i class="bi bi-cpu"></i>
|
||||
</td>
|
||||
<td th:text="${colName}">
|
||||
<td class="fw-bold" th:text="${colName}">
|
||||
</td>
|
||||
<td th:text="${object.compute(colName)}">
|
||||
</td>
|
||||
|
Loading…
x
Reference in New Issue
Block a user