2013-03-25 10:15:01.0|分类: struts源码分析|浏览量: 1542
struts2 自定义标签说明:A、继承ComponentTagSupport,获取jsp页面中的属性值 B、承Component类是为了从Struts2中的ValueStack中获得相对应的值 1、继承ComponentTagSupport类是为了获得JSP页面中用户自定义的标签中设置的属性值,并包装成Component对象
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.struts2.components.Component; import org.apache.struts2.views.jsp.ComponentTagSupport; import com.opensymphony.xwork2.util.ValueStack; /** * 自定义超链接标签 * 作用:检测用户是否有操作该标签的权限,如果该用户有操作该标签的权限,在页面显示超链接 * 如果用户没有操作该标签的权限,页面上不输出该标签 * */ public class ATag extends ComponentTagSupport { private String params; private String opcode; private String style; private String id; private String clasz; private String title; //标签属性title private String onclick ; private HttpServletRequest req; private HttpServletResponse res; @Override public Component getBean(ValueStack stack, HttpServletRequest req, HttpServletResponse res) { this.req = req; this.res = res; return new A(stack,req); } public void setParams(String params) { this.params = params; } public void setOpcode(String opcode) { this.opcode = opcode; } public void setCalcpid(String calcpid) { this.calcpid = calcpid; } public void setReq(HttpServletRequest req) { this.req = req; } public void setRes(HttpServletResponse res) { this.res = res; } public void setStyle(String style) { this.style = style; } public void setId(String id) { this.id = id; } public void setClasz(String clasz) { this.clasz = clasz; } public void setTitle(String title) { this.title = title; } public void setOnclick(String onclick) { this.onclick = onclick; } @Override protected void populateParams() { super.populateParams(); A a = (A)component; a.setClasz(clasz); a.setId(id); a.setOpcode(opcode); a.setParams(params); a.setStyle(style); a.setTitle(title); a.setOnclick(onclick); HttpSession session = req.getSession(); AuthBean authBean = (AuthBean)session.getAttribute(Constants.ATTR_AUTHBEAN); a.setAuthBean(authBean); } } 注释:ATag重写的两个方法是: public abstract class ComponentTagSupport extends StrutsBodyTagSupport { protected Component component; public abstract Component getBean(ValueStack stack, HttpServletRequest req, HttpServletResponse res); public int doEndTag() throws JspException { component.end(pageContext.getOut(), getBody()); component = null; return EVAL_PAGE; } public int doStartTag() throws JspException { component = getBean(getStack(), (HttpServletRequest) pageContext.getRequest(), (HttpServletResponse) pageContext.getResponse()); Container container = Dispatcher.getInstance().getContainer(); container.inject(component); populateParams(); boolean evalBody = component.start(pageContext.getOut()); if (evalBody) { return component.usesBody() ? EVAL_BODY_BUFFERED : EVAL_BODY_INCLUDE; } else { return SKIP_BODY; } } protected void populateParams() { } public Component getComponent() { return component; } } ComponentTagSupport类中声明了全局变量component,doStartTag()方法调用抽象方法getBean()生成component对象,这就是为什么我们要覆写getBean()方法。然后调用了 populateParams()方法,最后调用了component.start。 EVAL_BODY_INCLUDE:把Body读入存在的输出流中, doStartTag()函数可用 EVAL_PAGE:继续处理页面, doEndTag()函数可用 SKIP_BODY:忽略对Body的处理, doStartTag()和doAfterBody()函数可用 SKIP_PAGE:忽略对余下页面的处理, doEndTag()函数可用 EVAL_BODY_TAG:已经废止,由EVAL_BODY_BUFFERED取代 EVAL_BODY_TAG:申请缓冲区,由setBodyContent()函数得到的BodyContent对象来处理tag的body,如果类实现了BodyTag,那么doStartTag()可用,否则非法。 2、继承Component类是为了从Struts2中的ValueStack中获得相对应的值 import java.io.IOException; import java.io.Writer; import java.util.HashMap; import javax.servlet.http.HttpServletRequest; import org.apache.struts2.components.Component; import com.opensymphony.xwork2.util.ValueStack; public class A extends Component { private String params; //参数 private String opcode; private String style; //标签属性风格 private String id; //标签属性id private String clasz; //标签属性calss private String title; //标签属性title private String onclick ; //标签属性onclick private AuthBean authBean; HttpServletRequest req ; public A(ValueStack stack,HttpServletRequest req) { super(stack); this.req = req; } public String getStyle() { return style; } public void setStyle(String style) { this.style = style; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getParams() { return params; } public void setParams(String params) { this.params = params; } public String getOpcode() { return opcode; } public void setOpcode(String opcode) { this.opcode = opcode; } public String getClasz() { return clasz; } public void setClasz(String clasz) { this.clasz = clasz; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getOnclick() { return onclick; } public void setOnclick(String onclick) { this.onclick = onclick; } public void setAuthBean(AuthBean authBean) { this.authBean = authBean; } @Override public boolean start(Writer writer) { boolean flag = false;//是否能访问本连接 UserRoleOperate operate = null; if(authBean != null){ authBean.getOperate(); //省略了业务逻辑 flag= true; } if(flag){ //如果有访问权限 StringBuffer href = new StringBuffer(); String contextpath = req.getContextPath(); String url = operate.getUrl(); href.append(contextpath+url); StringBuffer link = new StringBuffer(); link.append("<A "); //首先添加action //判断是否为空,如果为空的话,不写href属性 if(!StringUtils.isBlank(url)){ link.append(" href=\"").append(href); //添加参数 if(!StringUtils.isBlank(params)){ link.append("?"+params); } link.append("\""); } //添加标签id属性 if(!StringUtils.isBlank(id)){ link.append(" id=\""+id+"\""); } //添加标签style属性 if(!StringUtils.isBlank(style)){ link.append(" style=\""+style+"\""); } //添加标签calss属性 if(!StringUtils.isBlank(clasz)){ link.append(" class=\""+clasz+"\""); } if(!StringUtils.isBlank(title)){ link.append(" title=\""+title+"\""); } if(!StringUtils.isBlank(onclick)){ link.append(" onclick=\""+onclick+"\""); } link.append(">"); System.err.println("----------------->"+link); try { writer.write(link.toString()); } catch (IOException e) { e.printStackTrace(); } } return super.start(writer); } @Override public boolean end(Writer writer, String body) { boolean flag = false;//是否能访问本连接 UserRoleOperate operate = null; if(authBean != null){ if(authBean != null){ authBean.getOperate(); //省略了业务逻辑 flag= true; } } if(flag){ try { writer.write("</A>"); } catch (IOException e) { e.printStackTrace(); } } return super.end(writer, body); } } 自己需要输出的逻辑通过writer输出字符串 这里请注意形式参数body中数据为空,为什么呢?为什么标签体的内容没有获得呢?,如果我们想自己控制body的显示呢? 获取body的方法时,重写Component类中的方法: /** * Overwrite to set if body shold be used. * @return always false for this component. */ public boolean usesBody() { return true; }设置返回值true,这时候你就可以获得body的值了,自己控制显示的情况。 3、创建标签库的描述文件 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd"> <taglib> <tlib-version>2.2.3</tlib-version> <jsp-version>1.2</jsp-version> <short-name>layout</short-name> <uri>/struts-layout-tags</uri> <display-name>"Struts Tags"</display-name> <description><![CDATA["To make it easier to access dynamic data; the Apache Struts framework includes a library of custom tags. The tags interact with the framework's validation and internationalization features; to ensure that input is correct and output is localized. The Struts Tags can be used with JSP FreeMarker or Velocity."]]></description> <tag> <name>a</name> <tag-class>com.fangdo.core.view.ATag</tag-class> <body-content>JSP</body-content> <attribute> <name>opcode</name> <required>true</required> <rtexprvalue>false</rtexprvalue> <description><![CDATA[opcode for this link]]></description> </attribute> <attribute> <name>calcpid</name> <required>false</required> <rtexprvalue>true</rtexprvalue> <description><![CDATA[calc product for this link]]></description> </attribute> <attribute> <name>params</name> <required>false</required> <rtexprvalue>true</rtexprvalue> <description><![CDATA[params for this link]]></description> </attribute> <attribute> <name>style</name> <required>false</required> <rtexprvalue>true</rtexprvalue> <description><![CDATA[style for this link]]></description> </attribute> <attribute> <name>id</name> <required>false</required> <rtexprvalue>true</rtexprvalue> <description><![CDATA[id for this link]]></description> </attribute> <attribute> <name>clasz</name> <required>false</required> <rtexprvalue>true</rtexprvalue> <description><![CDATA[clasz for this link]]></description> </attribute> <attribute> <name>title</name> <required>false</required> <rtexprvalue>true</rtexprvalue> <description><![CDATA[title for this link]]></description> </attribute> <attribute> <name>onclick</name> <required>false</required> <rtexprvalue>true</rtexprvalue> <description><![CDATA[onclick for this link]]></description> </attribute> </tag> </taglib>4、 web.xml中添加标签库说明 <jsp-config> <taglib> <taglib-uri>/struts-layout-tags.tld</taglib-uri> <taglib-location>/WEB-INF/struts-layout-tags.tld</taglib-location> </taglib> </jsp-config>5、 JSP页面中添加标签库说明,及使用标签 <%String jxc4_param = "id="+ cc.getId()+"&height=450&width=750"; %> <layout:a opcode="JXC_4" params="<%=jxc4_param %>" clasz="thickbox" title="商户详情"> 详情 </layout:a> 这里有个问题,比如某资源url,要在自定义标签中取得包含在标签内的a href,要如何做? 比如 <s:authorize url="......"> <a href="xxx.action"/> </s:authorize> 我要取得a href=xxx.action,然后 传入自定义标签类中,获得这个URL对应的能访问的角色有多少个,这个如何实现呢?谢谢 引用来自“jackyrong”的评论 <layout:a opcode="JXC_4" params="<%=jxc4_param %>" clasz="thickbox" title="商户详情"> 引用来自“jackyrong”的评论感觉这个有点麻烦,加入页面有很多连接,每个连接都必须有用这个标签管理呀,有什么好的方法?我想先加载所有连接,然后根据权限变灰色 引用来自“jackyrong”的评论我这边依然想用自定义标签去做,重写<a href方法,这样页面中凡是有a href的地方,都可以根据权限变灰色 |