上篇已介绍了JSF Tag类的开发,本篇将继续介绍JSF Renderer的开发。
Renderer类是JSF组件开发中一个较重要的类,该类主要功能是在Java和HTML之间的转换,在响应阶段将Java组件的属性转换为HTML代码,在接受请求阶段将HTML Request中传来的资料转换为Java组件的属性。
开发Renderer类时需要集成javax.faces.render.Renderer类,需实现其中的encode和decode方法,分别用来用来转换HTML和接受HTML值。
在Render过程中,有一个难点就是如何将组件中的CSS,Javascript和图片加载到客户端,这里我们会新增一个JSF Phase监听器,用来监听RESTORE_VIEW阶段,判断所请求资源是否为组件所用到的资源,如果请求资源是组件用到的CSS等资源,则直接将资源写到Response中。
Renderer类代码如下:
- package net.moon.jsf.customer.render;
- import java.io.IOException;
- import javax.faces.FacesException;
- import javax.faces.component.UIComponent;
- import javax.faces.context.FacesContext;
- import javax.faces.context.ResponseWriter;
- import javax.faces.render.Renderer;
- import net.moon.jsf.customer.component.HtmlDropdownList;
- public class DropdownListRenderer extends Renderer {
- private static final String SELECTOR = "_SELECTOR";
- private static final String AREA = "_AREA";
- private final static String INPUT = "_INPUT";
- private final static String IMAGE = "_IMAGE";
- public final static String UNIQURE_JS_KEY = "resource/moonscript.js.jsf";
- public final static String UNIQURE_CSS_KEY = "resource/mooncomponent.css.jsf";
- public final static String UNIQURE_IMAGE_KEY = "resource/dropdownList.png.jsf";
- public final static String UNIQURE_AJAX_KEY = "moonDDL.jsf";
- @Override
- public void decode(FacesContext context, UIComponent component) {
- // TODO Auto-generated method stub
- super.decode(context, component);
- }
- private void renderResourceOnce(FacesContext context) throws IOException {
- // render javascript to client
- Object isRendered = context.getExternalContext().getRequestMap().get(
- UNIQURE_JS_KEY);
- ResponseWriter out = context.getResponseWriter();
- out.write("/n");
- if (isRendered != null && (Boolean) isRendered) {
- } else {
- // rendered the javascript
- out.startElement("script", null);
- out.writeAttribute("type", "text/javascript", null);
- out.writeAttribute("src", UNIQURE_JS_KEY, null);
- out.endElement("script");
- context.getExternalContext().getRequestMap().put(UNIQURE_JS_KEY,
- true);
- }
- out.write("/n");
- isRendered = context.getExternalContext().getRequestMap().get(
- UNIQURE_CSS_KEY);
- if (isRendered != null && (Boolean) isRendered) {
- } else {
- // rendered this css
- out.startElement("link", null);
- out.writeAttribute("rel", "stylesheet", null);
- out.writeAttribute("type", "text/css", null);
- out.writeAttribute("href", UNIQURE_CSS_KEY, null);
- out.endElement("link");
- out.write("/n");
- context.getExternalContext().getRequestMap().put(UNIQURE_CSS_KEY,
- true);
- }
- }
- @Override
- public void encodeBegin(FacesContext context, UIComponent component)
- throws IOException {
- // TODO Auto-generated method stub
- super.encodeBegin(context, component);
- renderResourceOnce(context);
- if (context == null || component == null) {
- throw new FacesException("context can't be null");
- }
- if (!(component instanceof HtmlDropdownList)) {
- throw new FacesException("error dropdownList object");
- }
- rendererInput(context, (HtmlDropdownList) component);
- rendererImage(context, (HtmlDropdownList) component);
- rendererOthers(context, (HtmlDropdownList) component);
- }
- private void rendererOthers(FacesContext context, HtmlDropdownList component)
- throws IOException {
- String clientId = component.getClientId(context);
- ResponseWriter out = context.getResponseWriter();
- out.startElement("div", component);
- out.writeAttribute("id", clientId + AREA, null);
- out.writeAttribute("class", "dropdown_area", null);
- out.startElement("select", component);
- out.writeAttribute("id", clientId + SELECTOR, null);
- out.writeAttribute("name", clientId + SELECTOR, null);
- out.writeAttribute("multiple", "multiple", null);
- out.writeAttribute("class", "dropdown_selector", null);
- out.writeAttribute("onchange", "giveValue();", null);
- out.endElement("select");
- out.endElement("div");
- }
- private void rendererImage(FacesContext context, HtmlDropdownList component)
- throws IOException {
- // TODO Auto-generated method stub
- String clientId = component.getClientId(context);
- ResponseWriter out = context.getResponseWriter();
- String imageURL = component.getImage();
- out.startElement("image", component);
- out.writeAttribute("src", imageURL == null ? UNIQURE_IMAGE_KEY
- : imageURL, null);
- out.writeAttribute("id", clientId + IMAGE, null);
- out.writeAttribute("name", clientId + IMAGE, null);
- out.writeAttribute("class", "dropdown_button", null);
- out.writeAttribute("onclick", "showSelector(this, '"
- + (component.getValueList() == null ? component
- .getValueExpression("valueList").getExpressionString()
- : component.getValueList()) + "');", null);
- out.endElement("image");
- }
- public DropdownListRenderer() {
- super();
- // TODO Auto-generated constructor stub
- }
- private void rendererInput(FacesContext context, HtmlDropdownList component)
- throws IOException {
- String clientId = component.getClientId(context);
- String root = context.getExternalContext().getRequestContextPath();
- ResponseWriter out = context.getResponseWriter();
- out.startElement("input", component);
- out.writeAttribute("type", "text", null);
- out.writeAttribute("id", clientId + INPUT, null);
- out.writeAttribute("name", clientId + INPUT, null);
- out.writeAttribute("class",
- component.getStyleClass() == null ? "dropdown_input"
- : component.getStyleClass(), null);
- String changeMethod = component.getValueChange();
- if (changeMethod != null) {
- out.writeAttribute("onchange", "callBack('" + root + "/"
- + UNIQURE_AJAX_KEY + "?ACTION=VALUECHANGE', '"
- + changeMethod + "', '');", null);
- }
- out.endElement("input");
- }
- }
Phase Listener代码如下:
- package net.moon.jsf.customer.listener;
- import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.InputStreamReader;
- import java.io.OutputStreamWriter;
- import java.io.PrintWriter;
- import java.net.URL;
- import java.net.URLConnection;
- import javax.el.ValueExpression;
- import javax.faces.event.PhaseEvent;
- import javax.faces.event.PhaseId;
- import javax.faces.event.PhaseListener;
- import javax.servlet.ServletOutputStream;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import net.moon.jsf.customer.render.DropdownListRenderer;
- public class DropDownListener implements PhaseListener {
- public void afterPhase(PhaseEvent event) {
- // TODO Auto-generated method stub
- String rootId = event.getFacesContext().getViewRoot().getViewId();
- String root = "/";
- if (rootId.endsWith(DropdownListRenderer.UNIQURE_JS_KEY.replace(".jsf",
- ".jsp"))) {
- handleResourceRequest(event, root
- + DropdownListRenderer.UNIQURE_JS_KEY, "text/javascript");
- } else if (rootId.endsWith(DropdownListRenderer.UNIQURE_CSS_KEY
- .replace(".jsf", ".jsp"))) {
- handleResourceRequest(event, root
- + DropdownListRenderer.UNIQURE_CSS_KEY, "text/javascript");
- } else if (rootId.endsWith(DropdownListRenderer.UNIQURE_IMAGE_KEY
- .replace(".jsf", ".jsp"))) {
- handleImageRequest(event, root
- + DropdownListRenderer.UNIQURE_IMAGE_KEY, "image/png");
- } else if (rootId
- .endsWith(root
- + DropdownListRenderer.UNIQURE_AJAX_KEY.replace(".jsf",
- ".jsp"))) {
- handleAjaxEvent(event);
- }
- }
- private void handleAjaxEvent(PhaseEvent event) {
- HttpServletResponse response = (HttpServletResponse) event
- .getFacesContext().getExternalContext().getResponse();
- PrintWriter out = null;
- Object req = event.getFacesContext().getExternalContext().getRequest();
- HttpServletRequest request = null;
- if (!(req instanceof HttpServletRequest)) {
- return;
- }
- request = (HttpServletRequest) req;
- String action = request.getParameter("ACTION");
- try {
- out = response.getWriter();
- ValueExpression ve = event.getFacesContext().getApplication()
- .getExpressionFactory().createValueExpression(
- event.getFacesContext().getELContext(), action,
- String.class);
- if (!ve.isLiteralText()) {
- out.write((String) ve.getValue(event.getFacesContext()
- .getELContext()));
- } else {
- out.write(ve.toString());
- }
- response.setStatus(HttpServletResponse.SC_OK);
- event.getFacesContext().responseComplete();
- } catch (IOException ex) {
- ex.printStackTrace();
- }
- }
- private void handleImageRequest(PhaseEvent event, String resource,
- String contentType) {
- resource = resource.replace(".jsf", "");
- URL url = this.getClass().getResource(resource);
- HttpServletResponse response = (HttpServletResponse) event
- .getFacesContext().getExternalContext().getResponse();
- ServletOutputStream out = null;
- response.setContentType(contentType);
- response.setStatus(200);
- InputStream input = null;
- try {
- input = url.openStream();
- out = response.getOutputStream();
- byte[] cache = new byte[1024];
- int readed = 0;
- while ((readed = input.read(cache)) != -1) {
- try {
- out.write(cache, 0, readed);
- } catch (Exception ex) {
- System.out.println("*****");
- ex.printStackTrace();
- }
- }
- input.close();
- out.flush();
- out.close();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- event.getFacesContext().responseComplete();
- }
- private void handleResourceRequest(PhaseEvent event, String resource,
- String contentType) {
- resource = resource.replace(".jsf", "");
- URL url = DropDownListener.class.getResource(resource);
- URLConnection conn = null;
- InputStream stream = null;
- BufferedReader bufReader = null;
- HttpServletResponse response = (HttpServletResponse) event
- .getFacesContext().getExternalContext().getResponse();
- OutputStreamWriter outWriter = null;
- String curLine = null;
- try {
- outWriter = new OutputStreamWriter(response.getOutputStream(),
- response.getCharacterEncoding());
- conn = url.openConnection();
- conn.setUseCaches(false);
- stream = conn.getInputStream();
- bufReader = new BufferedReader(new InputStreamReader(stream));
- response.setContentType(contentType);
- response.setStatus(200);
- while (null != (curLine = bufReader.readLine())) {
- outWriter.write(curLine + "/n");
- }
- outWriter.flush();
- outWriter.close();
- event.getFacesContext().responseComplete();
- } catch (Exception e) {
- String message = "Can't load resource:" + url.toExternalForm();
- System.err.println(message);
- e.printStackTrace();
- }
- }
- public void beforePhase(PhaseEvent event) {
- // TODO Auto-generated method stub
- }
- public PhaseId getPhaseId() {
- // TODO Auto-generated method stub
- return PhaseId.RESTORE_VIEW;
- }
- }
本篇就介绍这些,下篇将对组件进行总体汇总,并提供完整代码下载。