Struts2 自定义JSP标签实现图形验证功能

jopen 9年前

先看一下官网关于component标签的注释:

Description

Renders an custom UI widget using the specified templates. Additional objects can be passed in to the template using the param tags.

Freemarker:

Objects provided can be retrieve from within the template via $parameters.paramname.

Jsp:

Objects provided can be retrieve from within the template via <s:property value="%{parameters.paramname}" />

In the bottom JSP and Velocity samples, two parameters are being passed in to the component. From within the component, they can be accessed as:-

Freemarker:

$parameters.get('key1') and $parameters.get('key2') or $parameters.key1 and $parameters.key2

Jsp:

<s:property value="%{parameters.key1}" /> and <s:property value="%{'parameters.key2'}" /> or <s:property value="%{parameters.get('key1')}" /> and <s:property value="%{parameters.get('key2')}" />

Currently, your custom UI components can be written in Velocity, JSP, or Freemarker, and the correct rendering engine will be found based on file extension.

Remember: the value params will always be resolved against the ValueStack so if you mean to pass a string literal to your component, make sure to wrap it in quotes i.e. value="'value1'" otherwise, the the value stack will search for an Object on the stack with a method of getValue1(). (now that i've written this, i'm not entirely sure this is the case. i should verify this manana)

 

If Jsp is used as the template, the jsp template itself must lie within the webapp itself and not the classpath. Unlike Freemarker or Velocity, JSP template could not be picked up from the classpath.

templateDir and theme attribute
The final path to the template will be built using the templateDir andtemplate attributes, like ${templateDir}/${theme}/${template}. If for example your component is under /components/html/option.jsp, you would have to set templateDir="components", theme="html" and template="options.jsp".

For any Struts tag that you use in your component, make sure that you set its templateDir="template"

-------------------------------------------------------------------------------------------------------------------------------------

self.tld:

<?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>1.0</tlib-version>   <jsp-version>1.2</jsp-version>   <short-name>map</short-name>     <tag>    <name>self</name>    <tag-class>servlet.SelfDefinationTag</tag-class>    <body-content>JSP</body-content>   </tag>  </taglib>

释义:这是JSP模板文件,定义了self标签,self标签的处理类为SelfDefinationTag。

SelfDefinationTag.jsp:

<%@ page language="java" pageEncoding="gb2312"%>  <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">  <%@taglib prefix="s" uri="/struts-tags"%>  <html>     <body>        <s:component template="/components/image.jsp templateDir="MyTemplate" theme="xhtml" />     </body>  </html>

释义:Struts2中的component标签是用来方便开发者定义自己开发的标签。(component:组件;template:模板)

这里定义了一个新的JSP文件,在该文件中使用component标签来调用image.jsp这个模板文件。

templateDir:定义模板文件所在的根目录名,若不显示声明则默认为"template";

theme:定义主题,若不显示声明则默认为"xhtml"。

因此,若templateDir和theme都不声明,则系统调用的模板文件就是/template/xhtml下的模板文件。

image.jsp:

<%@ page language="java"  pageEncoding="gb2312"%>  <%@ taglib uri="Self" prefix="s" %>  <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">  <html>    <body>        <s:self></s:self>    </body>  </html>

释义:自定义标签<s:self>,具体的标签含义在下面的SelfDefinationTag标签处理类。

SelfDefinationTag.java:

package servlet;    import java.io.IOException;    import javax.servlet.ServletContext;  import javax.servlet.http.HttpServletRequest;  import javax.servlet.jsp.JspException;  import javax.servlet.jsp.JspWriter;  import javax.servlet.jsp.tagext.TagSupport;    public class SelfDefinationTag extends TagSupport {   private static final long serialVersionUID = 1L;   String contextPath;      public int doStartTag() throws JspException {       JspWriter out = pageContext.getOut();     try{      out.println("<img src=\"..\\validateImage\"/>");     }catch (IOException ioe1){      ioe1.printStackTrace();     }          return EVAL_BODY_INCLUDE  ;   }     public String getContextPath( HttpServletRequest req ) {         String servletPath = req.getServletPath();         ServletContext servletContext = pageContext.getServletContext();         String realPath = servletContext.getRealPath( servletPath );         int lastSlash = realPath.lastIndexOf( System.getProperty( "file.separator" ) );         if ( lastSlash > -1 ) {            String contextPath = realPath.substring( 0, lastSlash + 1 );            return contextPath;         }         return "";      }       }

释义:通过实现Struts2的TagSupport接口定义了一个标签处理类,重写了doStartTag()方法。这个自定义标签只是插入了一段HTML图像代码。

注意<img src="../validateImage" />其中的“../”不能掉,它是上下文路径的表示,默认路径是WebRoot,这和Html中访问不同目录层次要加“../”是一样的道理。

ValidateImage.java:

package servlet;    import java.awt.Color;  import java.awt.Font;  import java.awt.Graphics;  import java.awt.image.BufferedImage;  import java.io.IOException;  import java.io.OutputStream;  import java.util.Random;    import javax.servlet.ServletException;  import javax.servlet.http.HttpServlet;  import javax.servlet.http.HttpServletRequest;  import javax.servlet.http.HttpServletResponse;    import com.sun.image.codec.jpeg.JPEGCodec;  import com.sun.image.codec.jpeg.JPEGEncodeParam;  import com.sun.image.codec.jpeg.JPEGImageEncoder;    public class ValidateImage extends HttpServlet {      protected void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException{   response.setContentType("image/jpeg");   createImage(response.getOutputStream());   response.setHeader("Pragma","No-cache");   response.setHeader("Cache-Control","no-cache");   response.setDateHeader("Expires", 0);     }      private void createImage(OutputStream out)throws IOException {      int width=60, height=20;    BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);      Graphics g = image.getGraphics();      Random random = new Random();      g.setColor(getRandColor(200,250));    g.fillRect(0, 0, width, height);      g.setFont(new Font("Times New Roman",1,15));      //g.setColor(new Color());    //g.drawRect(0,0,width-1,height-1);      g.setColor(getRandColor(160,200));    for (int i=0;i<155;i++)    {     int x = random.nextInt(width);     int y = random.nextInt(height);            int xl = random.nextInt(12);            int yl = random.nextInt(12);     g.drawLine(x,y,x+xl,y+yl);    }      //String rand = request.getParameter("rand");    //rand = rand.substring(0,rand.indexOf("."));    String sRand="";    for (int i=0;i<4;i++){        String rand=String.valueOf(random.nextInt(10));        sRand+=rand;        g.setColor(new Color(20+random.nextInt(110),20+random.nextInt(110),20+random.nextInt(110)));        g.drawString(rand,13*i+6,16);    }    //  session.setAttribute("rand",sRand);      g.dispose();      JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);    JPEGEncodeParam param  = encoder.getDefaultJPEGEncodeParam(image);    param.setQuality(1.0f, false);    encoder.setJPEGEncodeParam(param);        try{     encoder.encode(image);    }catch (IOException ioe){     ioe.printStackTrace();    }     }      Color getRandColor(int fc,int bc){          Random random = new Random();          if(fc>255) fc=255;          if(bc>255) bc=255;          int r=fc+random.nextInt(bc-fc);          int g=fc+random.nextInt(bc-fc);          int b=fc+random.nextInt(bc-fc);          return new Color(r,g,b);          }           }

释义:生成动态数字图的servlet类,在web.xml中也有该servlet的映射定义。

web.xml:

<?xml version="1.0" encoding="GB2312"?>  <web-app >   <servlet>    <servlet-name>ValidateImage</servlet-name>    <servlet-class>servlet.ValidateImage</servlet-class>   </servlet>     <servlet-mapping>    <servlet-name>ValidateImage</servlet-name>    <url-pattern>/validateImage</url-pattern>   </servlet-mapping>     <filter>    <filter-name>struts2</filter-name>    <filter-class>     org.apache.struts2.dispatcher.FilterDispatcher    </filter-class>   </filter>      <filter-mapping>    <filter-name>struts2</filter-name>    <url-pattern>*.action</url-pattern>   </filter-mapping>         <filter-mapping>          <filter-name>struts2</filter-name>          <url-pattern>*.jsp</url-pattern>      </filter-mapping>     <welcome-file-list>    <welcome-file>index.jsp</welcome-file>   </welcome-file-list>     <taglib>    <taglib-uri>Self</taglib-uri>    <taglib-location>/WEB-INF/tlds/self.tld</taglib-location>   </taglib>  </web-app>

释义:注意过滤器<filter-mapping>中不能用<url-pattern>/*</url-pattern>(拦截所有HTTP请求),而是只过滤.jsp和.action请求(不过滤servlet请求),这点一定要注意,否则异常:
21:51:16,907 WARN  [Dispatcher] Could not find action or result
There is no Action mapped for namespace / and action name validateImage. - [unknown location] 

struts.xml:

<?xml version="1.0" encoding="gb2312"?>  <!DOCTYPE struts PUBLIC  "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"  "http://struts.apache.org/dtds/struts-2.0.dtd">  <struts>   <package name="C05.7" extends="struts-default">    </package>  </struts>

释义:struts.xml中不用任何配置。

整体思路:self.tld文件用<taglib>自定义了标签<s:self>;此模板的核心含义,即标签处理类SelfDefinationTag.java。image.jsp文件调用了自定义的标签<s:self></s:self>,此文件即是JSP模板文件(调用了自定义标签的JSP文件)。这样一来,自定义JSP标签<s:self>就完成了,功能集中于image.jsp中了(即完成了self标签的功能)。之后在view层SelfDefination.jsp文件中用<s:component>标签调用image.jsp这个模板就行了。至于ValidateImage.java,这是一个独立的产生动态数字图片"流"的servlet类。在web.xml中定义了url映射及过滤拦截。

 

地址栏输入:http://localhost:8080/C05.7/jsp/SelfDefinationTag.jsp 输出结果为: