JSF自定义组件之五 JSF实现-Renderer
2008-09-01 11:46
549 查看
上篇已介绍了JSF Tag类的开发,本篇将继续介绍JSF Renderer的开发。<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
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;
}
}
本篇就介绍这些,下篇将对组件进行总体汇总,并提供完整代码下载。
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;
}
}
本篇就介绍这些,下篇将对组件进行总体汇总,并提供完整代码下载。
相关文章推荐
- JSF自定义组件之三 JSF实现-Tag
- JSF自定义组件之四 JSF实现-Component
- dql组件结果页面实现自定义效果
- jsf 创建自定义组件
- Android自定义组件系列【3】——自定义ViewGroup实现侧滑
- 自定义View实现广告位轮播图barner组件
- 微信小程序之自定义组件的实现代码(附源码)
- 开始为exoplatform实现ajax-jsf组件。
- 自定义JSF通用分页组件
- Android自定义组件系列【14】——Android5.0按钮波纹效果实现
- JSF2自定义组件编程系列 第七部分
- 自定义组件实现三种进度条
- Android自定义组件之日历控件-精美日历实现(内容、样式可扩展)
- JSF2自定义组件编程系列 第六部分
- 自定义QWidget组件实现模态窗口功能
- AJAX+JSF组件实现高性能的文件上载
- jsf自定义toolbar组件
- jsf自定义toolbar组件
- jsf自定义toolbar组件
- jsf自定义toolbar组件