Прежде всего, вы должны рассмотреть вопрос о реструктуризации вашего приложения в виде слоев. Вам, по крайней мере, нужен 3 уровня, DAO, Service и WebService.
Все, что касается базы данных и JPA, должно быть в вашем слое DAO. И все связанные с json вещи должны быть на вашем уровне WebService. Уровень обслуживания должен управлять транзакцией и связью между веб-сервисом и уровнем dao.
Сначала давайте поговорим о вашем уровне веб-службы. Ваши объекты JSON, вероятно, поступают из веб-службы Restful. Поскольку почти все фреймворки поддерживают json marshalling/unmarshalling, нецелесообразно вручную анализировать объекты передачи данных. Под этим я подразумеваю, вы можете предпочесть объявить класс FieldDto и передать его экземпляры вместо JSONObject. Вот пример FieldDto
. Это ПОЖО.
public class FieldDto {
private String prodId;
private String prodName;
// Getters & Setters etc.
}
Вы можете легко вывести/развязать json с помощью GSON или Jackson. Вероятно, ваша инфраструктура имеет один из них по умолчанию для обработки json-преобразования.
Следующий слой - это служебный уровень. На уровне обслуживания вы управляете своими транзакциями и конвертируете объекты DTO в то, что может легко понять ваш уровень DAO. В этом случае ваш уровень обслуживания пройдет fieldDto.getProdId()
и fielDto.getProdName()
на уровень DAO.
Ваш последний слой - слой DAO. Сначала давайте изменим вашу подпись метода.
public List <Product> getProducts(String prodId, String prodName) {
CriteriaBuilder criteriaBuilder = getEntityManager().getCriteriaBuilder();
CriteriaQuery <Product> criteriaQuery = criteriaBuilder.createQuery(Product.class);
Root <Product> root = criteriaQuery.from(Product.class);
List <Predicate> p = new ArrayList <Predicate>();
if(prodId != null){
p.add(criteriaBuilder.like(root.get(Product_.prodId),prodId));
}
if(prodName != null){
p.add(criteriaBuilder.like(root.get(Product_.prodName), prodName));
}
if(!p.isEmpty()){
Predicate[] pr = new Predicate[p.size()];
p.toArray(pr);
criteriaQuery.where(pr);
}
return getEntityManager().createQuery(criteriaQuery).getResultList();
}
Это не оно. Этот код по-прежнему нуждается в улучшении. В одном из моих проектов я создаю свободный api для управления всеми деталями шаблонов. Когда вы начнете писать другие классы DAO, вы поймете, что некоторые из блоков кода повторяются снова и снова.
Ниже приведен пример свободного api. Вы можете создать свою версию.
import javax.persistence.EntityManager;
import javax.persistence.LockModeType;
import javax.persistence.PersistenceException;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.*;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.CollectionAttribute;
import javax.persistence.metamodel.PluralAttribute;
import javax.persistence.metamodel.SingularAttribute;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Vector;
public final class SimpleSelectBuilder<E extends Entity> {
private final EntityManager entityManager;
private final CriteriaBuilder criteriaBuilder;
private final CriteriaQuery<E> criteriaQuery;
private final Root<E> root;
private final Collection<Predicate> predicates;
private Integer first = null;
private Integer max = null;
private LockModeType lockModeType = null;
public SimpleSelectBuilder(final EntityManager entityManager, final Class<E> entityClazz) {
this.entityManager = entityManager;
this.criteriaBuilder = entityManager.getCriteriaBuilder();
this.criteriaQuery = this.criteriaBuilder.createQuery(entityClazz);
this.root = criteriaQuery.from(entityClazz);
this.predicates = new Vector<>();
}
public SimpleSelectBuilder<E> and(final Attribute attribute, final Object value) {
final Expression expression = this.getExpression(attribute, root);
this.predicates.add(criteriaBuilder.equal(expression, value));
return this;
}
public SimpleSelectBuilder<E> andNotIn(final Attribute attribute, final Collection<Object> values) {
final Expression expression = this.getExpression(attribute, root);
this.predicates.add(criteriaBuilder.not(expression.in(values)));
return this;
}
public SimpleSelectBuilder<E> andIn(final Attribute attribute, final Collection<Object> values) {
final Expression expression = this.getExpression(attribute, root);
this.predicates.add(expression.in(values));
return this;
}
public SimpleSelectBuilder<E> andContains(final Attribute attribute, final Object value) {
final Expression expression = this.getExpression(attribute, root);
this.predicates.add(criteriaBuilder.isMember(value, expression));
return this;
}
public SimpleSelectBuilder<E> orderByAsc(final Attribute attribute) {
final List<Order> orders = new ArrayList<>();
if (this.criteriaQuery.getOrderList() != null) {
orders.addAll(this.criteriaQuery.getOrderList());
}
orders.add(criteriaBuilder.asc(this.getExpression(attribute, root)));
this.criteriaQuery.orderBy(orders.toArray(new Order[orders.size()]));
return this;
}
public SimpleSelectBuilder<E> orderByDesc(final Attribute attribute) {
List<Order> orders = this.criteriaQuery.getOrderList();
if (orders == null) {
orders = new ArrayList<>();
}
orders.add(criteriaBuilder.desc(this.getExpression(attribute, root)));
this.criteriaQuery.orderBy(orders.toArray(new Order[orders.size()]));
return this;
}
public SimpleSelectBuilder<E> setFirst(Integer first) {
this.first = first;
return this;
}
public SimpleSelectBuilder<E> setMax(Integer max) {
this.max = max;
return this;
}
public SimpleSelectBuilder<E> setLockModeType(LockModeType lockModeType) {
this.lockModeType = lockModeType;
return this;
}
public List<E> getResultList() {
final TypedQuery<E> query = this.prepareQuery();
if (lockModeType != null) {
query.setLockMode(lockModeType);
}
if (first != null) {
query.setFirstResult(first);
}
if (max != null) {
query.setMaxResults(max);
}
return query.getResultList();
}
public List<E> getCacheableResultList() {
final TypedQuery<E> query = this.prepareQuery();
if (lockModeType != null) {
query.setLockMode(lockModeType);
}
if (first != null) {
query.setFirstResult(first);
}
if (max != null) {
query.setMaxResults(max);
}
query.setHint("org.hibernate.cacheable", true);
query.setHint("org.hibernate.cacheMode", "NORMAL");
return query.getResultList();
}
public E getSingleResult() {
final TypedQuery<E> query = this.prepareQuery();
if (lockModeType != null) {
query.setLockMode(lockModeType);
}
return query.getSingleResult();
}
public E getCacheableSingleResult() {
final TypedQuery<E> query = this.prepareQuery();
if (lockModeType != null) {
query.setLockMode(lockModeType);
}
query.setHint("org.hibernate.cacheable", true);
query.setHint("org.hibernate.cacheMode", "NORMAL");
return query.getSingleResult();
}
private TypedQuery<E> prepareQuery() {
this.criteriaQuery.where(this.predicates.toArray(new Predicate[this.predicates.size()]));
return this.entityManager.createQuery(criteriaQuery);
}
private <T> Expression<T> getExpression(final Attribute attribute, final From<E, T> from) {
if (attribute instanceof SingularAttribute) {
SingularAttribute singularAttribute = (SingularAttribute) attribute;
return from.get(singularAttribute);
} else if (attribute instanceof PluralAttribute) {
PluralAttribute pluralAttribute = (PluralAttribute) attribute;
return from.get(pluralAttribute);
} else {
throw new PersistenceException("Attribute type of '" + attribute
+ "' must be one of [SingularAttribute, PluralAttribute].");
}
}
private <T> Join<E, T> getJoinExpression(final Attribute attribute, final From<E, T> from) {
if (attribute instanceof SingularAttribute) {
final SingularAttribute singularAttribute = (SingularAttribute) attribute;
return from.join(singularAttribute);
} else if (attribute instanceof CollectionAttribute) {
final CollectionAttribute collectionAttribute = (CollectionAttribute) attribute;
return from.join(collectionAttribute);
} else {
throw new PersistenceException("Attribute type of '" + attribute
+ "' must be one of [SingularAttribute, PluralAttribute].");
}
}
public SimpleSelectBuilder<E> joinAnd(final Attribute attribute, final Object value, final Attribute... joinOn) {
Join tableJoin = null;
for (final Attribute join : joinOn) {
if (tableJoin == null) {
tableJoin = this.getJoinExpression(join, root);
} else {
tableJoin = this.getJoinExpression(join, tableJoin);
}
}
if (tableJoin == null) {
throw new PersistenceException("SelectBuilder cannot construct your join statement");
}
final Expression expression = this.getExpression(attribute, tableJoin);
this.predicates.add(criteriaBuilder.equal(expression, value));
return this;
}
}
Если вы используете это. Чем ваш метод станет таким.
public List <Product> getProducts(String prodId, String prodName) {
// TODO add like statement to SimpleSelectBuilder
return new SimpleSelectBuilder<Product>(this.getEntityManager(), Product.class)
.and(Product_.prodId, prodId))
.and(Product_.prodName, prodName))
.getResultList();
}
Это будет лучше, если вы написать свой собственный SimpleSelectBuilder для обработки стереотипных блоков коды и увеличить повторное использование. Например, вам нужно добавить оператор like
в код выше.
Управление всеми слоями, транзакциями, пулами соединений и т. Д. Займет много времени. Вместо этого вы можете захотеть рассмотреть промежуточное программное обеспечение, чтобы управлять всем этим для вашего. В моих проектах я предпочитаю Весну.
Прежде всего за подробное объяснение. Я использую EJB, а не Spring. Да, я разбиваюсь на разные слои. Я проанализирую ваше решение. Оценил. – user75ponic
@bhdrkn Это потрясающее решение!Я скопировал ваш SimpleSelectBuilder и добавил около 6-8 других методов (например, «like», «include» (aka join), «or», «subEntityPropertyEquals» (чтобы я мог фильтровать родителя по одному из свойств его дочернего элемента и группу из других) .Я перехожу от C# к Java и, используя этот свободный класс строителей, я создал что-то похожее на LINQ, так что, надеюсь, это поможет мне и моей команде сделать переход! Еще раз спасибо. – HenryC