Мы используем сущности-сущности JPA в качестве нашей модели для Spring MVC-контроллера на странице jsp. Одна из наших страниц jsp - это частичный вид этого объекта, который не отображает все свойства. Всякий раз, когда мы пытаемся обновить нашу сущность, используя уровень сервиса с контроллера, свойства, используемые в форме jsp, сохраняются, а все остальные удаляются. Каков правильный способ справиться с этой ситуацией? Мы не хотим указывать скрытые поля в форме.Как сохранить определенные свойства атрибута модели сущности JPA с страницы JSP
Так что в этом случае, когда контроллер вызывает метод service.update (client), поле имени будет пустым, поскольку оно не существует в form.jsp.
form.jsp
<form:form modelAttribute="client" method="get" action="${action}">
<table width="100%">
<tr>
<td>
<table>
<tr>
<td valign="top"><spring:message code="label.tradeOrderManagementSystem"/>:</td>
<td>
<form:select path="tradeOrderManagementSystems" >
<form:options items="${tradeOrderManagementSystemList}" itemValue="id" itemLabel="name" />
</form:select>
<a href="<spring:url value="/tradeOrderManagementSystem/add"/>" class="addAndReturn"><span><spring:message code="add"/></span></a>
</td>
<td>
<form:errors path="tradeOrderManagementSystems" cssClass="errors" />
</td>
</tr>
<tr><td></td><td> </td></tr>
</table>
</td>
</tr>
</table>
<input type="hidden" name="submitted" value="true">
Контроллер
@RequestMapping("/{id}/edit")
public ModelAndView edit(HttpServletRequest request,
HttpServletResponse response,
@ModelAttribute("client") Client client,
BindingResult result,
@PathVariable("id") int id,
Model model) {
ControllerContext ctx = new ControllerContext(request, response);
init(ctx);
setAdvancedSearchAvailable(ctx, true);
buildShowAndEditVerticalMenu(ctx, id, false);
if (id == 0) {
result.addError(new ObjectError("client", getMessage("error.idNeeded")));
return getModelAndView(ctx, "itEfficiencies/form");
} else {
if (!isSubmission(ctx)) {
client = clientService.find(id);
model.addAttribute("client", client);
fillClientForm(model);
return getModelAndView(ctx, "itEfficiencies/form");
} else {
//clientValidator.validate(client, result);
if (result.hasErrors()) {
fillClientForm(model);
return getModelAndView(ctx, "itEfficiencies/form");
} else {
try {
//checkClientProperties(client);
client.setId(id);
client = clientService.update(client); //method updates only form fields and nulls out all others
} catch (Exception e) {
e.printStackTrace();
result.addError(new ObjectError("client", getMessage("error.save")));
fillClientForm(model);
return getModelAndView(ctx, "itEfficiencies/form");
}
return getModelAndView(ctx, "/staffingByClient/" + client.getId() + "/show", true);
}
}
}
}
Client.java
@Entity
public class Client extends AbstractEntity<Integer> {
private static final long serialVersionUID = 1L;
public static final String FIND_BY_NAME = "Client.FIND_BY_NAME";
public static final String COUNT_BY_NAME = "Client.COUNT_BY_NAME";
@Basic(optional = false)
@Column(nullable = false, length = 125)
private String name;
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(inverseJoinColumns = {
@JoinColumn(name = "trade_order_management_system_id")}, uniqueConstraints =
@UniqueConstraint(name = "UK_client_trade_order_mgmt_client_id_trade_order_mgmt_id",
columnNames = {"client_id", "trade_order_management_system_id"}))
@ForeignKey(name = "FK_client_trade_order_management_systems_client_id",
inverseName = "FK_client_trade_order_mgmt_sys_trade_order_management_system_id")
private List<TradeOrderManagementSystem> tradeOrderManagementSystems;
public Client() {
}
public Client(Integer id) {
this.id = id;
}
public Client(Integer id, String name) {
this.id = id;
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<TradeOrderManagementSystem> getTradeOrderManagementSystems() {
return tradeOrderManagementSystems;
}
public void setTradeOrderManagementSystems(List<TradeOrderManagementSystem> tradeOrderManagementSystems) {
this.tradeOrderManagementSystems = tradeOrderManagementSystems;
}
@Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Client)) {
return false;
}
Client other = (Client) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
}
методы обслуживания
public abstract class CrudService<T, ID extends Serializable> extends DAOImpl<T, ID> {
/**
* Updates an entity from an existing entity.
*
* @since 0.0.1
*
* @param entity
* @return the managed instance of the updated entity
*/
@Override
@Transactional(rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED)
public T update(T entity, ID id) {
return super.update(assignDefaultValues(entity), id);
}
}
public abstract class DAOImpl<T, ID extends Serializable> implements DAO<T, ID> {
private Class<T> persistentClass;
@PersistenceContext(unitName = "krfsPersistenceUnit")
protected EntityManager entityManager;
/**
* Instantiates an instance of this class and sets the <code>persistentClass</code>
* based on the identifier type
*
* @since 0.0.1
*/
public DAOImpl() {
this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}
/**
* @since 0.0.1
*
* @return the type to be persisted
*/
@Override
public Class<T> getPersistentClass() {
return persistentClass;
}
/**
* Updates an entity from an existing entity.
*
* @since 0.0.1
*
* @param entity
* @param id the identifier of the entity
*
* @return the managed instance of the updated entity
*/
@Override
public T update(T entity, ID id) {
//Find a managed instance of the entity first and copy the properties
//to the passed in entity before merging. This ensures that entityManager
//will not create a new entity with merge.
Object ref = this.entityManager.getReference(persistentClass, id);
if (ref != null) {
BeanUtils.copyProperties(entity, ref);
}
return (T) this.entityManager.merge(ref);
}
}
Я также знаю, что использование какого-либо DTO для модели также является решением, но просто не имеет смысла, что часть модели уничтожена, поскольку форма определяет только определенные поля Модели.Если я подталкиваю модель к ModelAndView, форма должна сохранять только то, что указано в Модели! – dukethrash