Bom, voltei a mexer com esse problema de PartialResponse no VRaptor e terminei aqui, acho que ficou bom estão vou colocar a solução que deve ajudar alguém, só está faltando criar uma CustomTag do JSP (tipo <xxx:ajax update=‘compId’ process=‘comp1Id’/> ) pra deixar bem parecido com JSF e ficar transparente para os programadores (é que aqui na minha empresa estamos saindo do JSF e indo para o Jquery + VRaptor em um projeto, então eu não quero assustar muito os programadores com o JQuery já que com o JSF (primefaces) o JQuery é bem escondido)
Vamos lá, como eu fiz(Parte Html):
nada demais no html, apenas o onclick do botão que chama a function ajax
<form class="form" id="form">
<label>Nome</label>
<input type="text" name="nome" id="inpNome"/>
<br/>
<label id="lblMsg">${mensagem}</label>
<input type="button" value="Ajax" id="btnAjax" onclick="ajax('<c:url value='/partial/teste/exec'/>', 'inpNome', 'lblMsg', event);"/>
</form>
JavaScript:
o sendId indica quais componentes terão os valores transmitidos na request e o updateId indica quais campos serão substituidos e também indica quais campos serão retornados pelo servidor.
Os 2 podem receber um ou mais inputs ou form, basta informar os ids separados por espaço.
function ajax (url, sendId, updateId, event){
event.preventDefault();
var selector = getSelectorByIds(sendId);
var data = '';
if(selector != null){
data = $(selector).serialize();
}
data += '&updateIds='+updateId;
$.get(url, data, function (html){
var updateSelector = getSelectorByIds(updateId);
if(updateSelector){
$html = $(html);
$(updateSelector).each(function (idx){
$(this).replaceWith($html.filter('#'+this.id));
$html.end();
});
}
}, 'html');
};
(Parte servidor)
Web.xml:
No web.xml eu mapeei o filtro para executar em requisições /partial/*, assim o programador pode escolher. Se ele colocar /partial antes da url então a resposta será parcial apenas dos componentes que ele passou o id, já se ele não colocar o /partial a resposta será completa porém o JQuery só vai substituir os componentes desejados.
Então fica na mão do programador /partial - Maior processamento no lado servidor, porém menor banda. Sem o /partial menor processamento do lado servidor porém maior uso da banda. Mas o ajax funciona normalmente com as duas opções, como depois vai ter um customTag isso vai virar um parametro boolean da tag.
<filter-mapping>
<filter-name>partialResponse</filter-name>
<url-pattern>/partial/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
Filtro
O filtro só troca o response tira o /partial do endereço e manda pro VRaptor processar
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
HttpServletRequest httpRequest = ((HttpServletRequest)request);
if (response.getCharacterEncoding() == null) {
response.setCharacterEncoding("UTF-8");
}
PartialResponseWrapper respAjax = new PartialResponseWrapper((HttpServletResponse) response, httpRequest.getParameter("updateIds"));
String path = ((HttpServletRequest)request).getServletPath();
httpRequest.getRequestDispatcher(path.replace("/partial", "")).forward(httpRequest, respAjax);
}
O código do PartialResponseWrapper e do PartialOutputStream são padrões para se fazer um wrapper de response então eu não vou colocar aqui para não aumentar demais o post, porém no flush() do OutputStream é que está o pulo do gato, que é o seguinte:
Estou usando esse HTMLParser: http://htmlparser.sourceforge.net/ assim não precisa transformar o HTML em XML
É passado pro outputstream quais os IDS que precisam ser retornados (através do parâmetro updateIds ali na linha 9 do código javascript e na linha 8 do filtro)
private byte[] getPartialResponse() throws IOException{
long t1 = System.currentTimeMillis();
try {
if(responseIds == null)return null;
OrFilter filter = createHtmlFilter();
byte[] bytes = getBytes();
Parser parser = Parser.createParser(new String(bytes, Charset.forName("UTF-8")), "UTF-8");
NodeList ex = null;
try {
ex = parser.extractAllNodesThatMatch(filter);
} catch (ParserException e) {
throw new IOException("Falha ao criar parser para a resposta AJAX", e);
}
return ex.toHtml().getBytes(Charset.forName("UTF-8"));
}finally {
System.out.println("TEMPO PARA GERAR RESPOSTA PARCIAL: " + (System.currentTimeMillis()-t1));
}
}
private OrFilter createHtmlFilter() {
String[] responseIds = updateIds == null || updateIds.length() == 0 ? null : updateIds.split(" ");
NodeFilter[] filters = new NodeFilter[responseIds.length];
for(int i = 0; i < responseIds.length; i++) {
filters[i] = new HasAttributeFilter("id", responseIds[i]);
}
return new OrFilter(filters);
}
Pronto com isso quando eu faço uma requisição para /partial/controller/metodo o método do controler é executado, porém, apenas os componentes que tenham os IDS informados na request é que serão devolvidos para o browser.
É isso, espero que ajude alguém, fiz apenas testes iniciais mas parece funcionar sem problemas, e o tempo para gerar a resposta Parcial não está passando de 20ms em paginas médias com (20 inputs).
Lucas valeu pela dica do response.