Se você fizesse da seguinte maneira, para popular sua tabela...
<c:forEach var="cliente" items="${dao.listarClientes}">
<table>
<tr>
// Primeiro, você printa os dados do seu cliente [no caso, ID e nome].
<td><input type="hidden" id="clienteID" value="${cliente.ID}" /></td>
<td><input type="text" id="clienteNome" value="${cliente.nome}" /></td>
// Logo após, você pega quais são os contatos desse cliente e printa também.
<c:forEach var="contato" items="${cliente.contatos}">
<table>
<tr>
// O ID do cliente logo acima que você queria.
<td><input type="hidden" id="clienteID" value="${cliente.ID}" /></td>
<td>${contato.status}</td>
<td><fmt:formatDate value="${contato.proximoContato.time}" pattern="dd/MM/yyyy"/></td>
<td><a href="registro-contato.jsp"\>Registros de Contato</a></td>
</tr>
</table>
</c:forEach>
</tr>
</table>
</c:forEach>
[Fiz no olho, mas dá pra ter uma ideia do que eu quis dizer].
Bom, com esse link, você redireciona para outra página de cadastro, é isso?
Você pode passar para sua outra página os valores do cliente que você necessita que, no caso, é o ID. Você vai colocar esse ID do cliente em um HiddenField, pois só você precisa saber que ele está lá, o cliente não. Daí, você cadastra normalmente, faz a chamada do seu Servlet. Nisso, você tem o ID do cliente em um HiddenField, e pode utilizar-se dele para cadastrar!
public class AdicionarContato extends HttpServlet {
private RequestDispatcher requestDispatcher = null;
public void execute(...) {
String errorMessage = null;
try {
Connection currentConnection = (Connection) request.getAttribute("conexao");
SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
DSOContato contatoDSO = new DSOContato(currentConnection);
Contato contatoEntity = new Contato();
contatoEntity.setProximoContato( dateFormat.parse(String.valueOf(request.getParameter("proximoContato"))) );
contatoEntity.setCliente( Integer.valueOf(String.valueOf(request.getParameter("clienteID"))) );
contatoEntity.setResumo( String.valueOf(request.getParameter("resumo")) );
contatoEntity.setStatus( String.valueOf(request.getParameter("status")) );
contatoDSO.createContato(contatoEntity);
requestDispatcher = request.getRequestDispatcher("/listarcontatos.jsp");
requestDispatcher.forward(request, response);
}
catch (SQLException errSQL) {
errorMessage = "Database error: " + errSQL.getMessage();
requestDispatcher = request.getRequestDispatcher("/error.jsp");
requestDispatcher.forward(request,response);
}
catch (Exception err) {
errorMessage = "General error: " + errSQL.getMessage();
requestDispatcher = request.getRequestDispatcher("/error.jsp");
requestDispatcher.forward(request,response);
}
}
}
Temos a classe de serviço:
public class DSOContato {
Connection currentConnection;
public DSOContato(Connection currentConnection) {
this.currentConnection = currentConnection;
}
public void createContato(Contato entityToCreate) throws SQLException {
DAOContato contatoDAO = new DAOContato(currentConnection);
contatoDAO.create(entityToCreate);
}
public List<Contato> loadContatosByCliente(Long clienteID) throws SQLException {
DAOContato contatoDAO = new DAOContato(currentConnection);
Map<String, Object> criteria = new HashMap<String, Object>();
criteria.put("cliente", clienteID);
return contatoDAO.loadByCriteria(criteria);
}
}
E a de persistência:
public class DAOContato {
Connection currentConnection;
public DAOContato(Connection currentConnection) {
this.currentConnection = currentConnection;
}
public void create(Contato entityToCreate) throws SQLException {
// Sua operação para adicionar o contato à base de dados.
}
public List<Contato> loadByCriteria(Map<String, Object> criteria) throws SQLException {
String selectSentence = "SELECT * FROM DBO.CONTATOS WHERE 1 = 1";
if (criteria != null) {
if (criteria.containsKey("cliente")) {
selectSentence = String.format("%s AND CLIENTE = %s", selectSentence, criteria.get("cliente"));
}
}
// popular uma coleção de contatos e retorná-la.
}
}
Agora, para buscar os clientes e seus contatos [do jeito que falei: uma coleção de contatos no cliente], faça algo do tipo:
public class DAOCliente {
Connection currentConnection;
public DAOCliente(Connection currentConnection) {
this.currentConnection = currentConnection;
}
public void create(Contato entityToCreate) throws SQLException {
// Sua operação para adicionar o contato à base de dados.
}
public List<Cliente> loadByCriteria(Map<String, Object> criteria) throws SQLException {
String selectSentence = "SELECT * FROM DBO.CLIENTES WHERE 1 = 1";
if (criteria != null) {
}
PreparedStatement selectStatement = currentConnection.prepareStatement(selectSentence);
ResultSet selectResult = selectStatement.executeQuery();
while (selectResult.next()) {
clientesCollection.add(loadEntity(selectResult, criteria));
}
}
private Cliente loadEntity(ResultSet selectResult, Map<String, Object> criteria) throws SQLException {
DSOContato contatoDSO = new DSOContato(currentConnection);
Cliente clienteEntity = new Cliente();
// preenche o objeto...
// e busca quais são os contatos do cliente!
clienteEntity.setContatos(contatoDSO.loadContatosByCliente(clienteEntity.getID()));
}
}
A partir dese objeto, você pode popular a tabela com o do modo que eu mostrei ali em cima!
Tá, ficou grande, mas espero que tenha sido útil de algum modo!
Abraços!