两级联动菜单的实现之一 - 用taglib实现上拉菜单
两级联动菜单的实现之一 --- 用taglib实现下拉菜单
整个类很简单,就是把数据从后台读取出来,放到map中,传递给标签类。
web.xml:声明标签,在web.xml的最后加入如下配置。
最近在项目里有一个功能点需要实现页面的菜单联动,具体场景描述:页面有三个输入:接口名称、接口版本和接口参数,前两者是下拉菜单,第三个是input标签,接口名称需要从数据库表动态生成,接口版本跟随接口名称的变化而变化,接口参数根据接口名称和接口版本来确定内容。我决定用taglib实现一个标签来满足接口名称从后台数据库读取的要求,再用ajax技术来实现菜单联动的效果。
一、taglib重写select标签
整个标签要实现上述功能,需要实现两个要点:首先当然是select标签的重写,其二就是操作数据库,提取满足需求的数据。
标签代码如下:
package com.vness.mytag; import java.io.IOException; import java.util.HashMap; import java.util.Iterator; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.DynamicAttributes; import javax.servlet.jsp.tagext.TagSupport; import com.vness.data.pullDownMenuData; public final class tagSelectExt extends TagSupport implements DynamicAttributes { /** * 控件名称 */ private String name; private String id; //数据库表名字 private String dbTable; //值列 private String valueCol; //展示列 private String nameCol; //数据集合 private HashMap paramMap = new HashMap() ; //默认选中 private String defaultSelected; //需要支持的属性标签 private String onChange; /** * option style * 0: 全部 * 1: 请选择 */ private String optStyle; public void setDynamicAttribute(String uri, String name, Object value) throws JspException { if ("id".equalsIgnoreCase(name)) { setId((String)value); return; } if ("name".equalsIgnoreCase(name)) { setName((String)value); return; } if ("dbTable".equalsIgnoreCase(name)) { setDbTable((String)value); return; } if ("valueCol".equalsIgnoreCase(name)) { setValueCol((String)value); return; } if ("nameCol".equalsIgnoreCase(name)) { setNameCol((String)value); return; } if ("defaultSelected".equalsIgnoreCase(name)) { setDefaultSelected((String)value); return; } if ("optStyle".equalsIgnoreCase(name)) { setOptStyle((String)value); return; } if ("onChange".equalsIgnoreCase(name)) { setOnChange((String)value); return; } } /* * Setter Mothed Start! */ public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDbTable() { return dbTable; } public void setDbTable(String dbTable) { this.dbTable = dbTable; } public String getValueCol() { return valueCol; } public void setValueCol(String valueCol) { this.valueCol = valueCol; } public String getNameCol() { return nameCol; } public void setNameCol(String nameCol) { this.nameCol = nameCol; } public String getDefaultSelected() { return defaultSelected; } public void setDefaultSelected(String defaultSelected) { this.defaultSelected = defaultSelected; } public String getOptStyle() { return optStyle; } public void setOptStyle(String optStyle) { this.optStyle = optStyle; } public void setId(String id) { this.id = id; } public void setOnChange(String value) { // TODO Auto-generated method stub this.onChange=value; } private void setParamMap() throws Exception { String condition=genSql(); pullDownMenuData pdd=new pullDownMenuData(); try { pdd.selectData(condition); } catch (Exception e) { // TODO Auto-generated catch block throw new Exception("查询数据失败!"+e); } paramMap=pdd.getData(); } /* * Setter Mothed End! */ private String genId() { if( id == null ) { id = "select_" + Math.random(); } return id; } public String genSql(){ StringBuffer buf = new StringBuffer(); buf.append("select distinct "); buf.append(nameCol+", "+valueCol+" "); buf.append("from "+ dbTable); return buf.toString(); } @Override public int doEndTag() throws JspException { //查询数据库,获取数据 try { setParamMap(); } catch (Exception e1) { // TODO Auto-generated catch block e1.printStackTrace(); } StringBuffer buf = new StringBuffer(); buf.append("<select "); buf.append("id='" + genId() + "' "); if (!(name==null||name.equalsIgnoreCase(""))) { buf.append("name='" + name + "' "); } if (!(onChange==null||onChange.equalsIgnoreCase(""))) { buf.append("onChange='" + onChange + "' "); } buf.append(" >"); if("0".equals(optStyle)){ buf.append("<option value=''>全部</option>"); } else if("1".equals(optStyle)){ buf.append("<option value=''>请选择</option>"); } if (paramMap != null) { Iterator iter = paramMap.keySet().iterator(); while (iter.hasNext()) { String key = (String) iter.next(); String value = (String) paramMap.get(key); buf.append("<option value='" + value + "'"); if (value.equalsIgnoreCase(defaultSelected)) { buf.append(" selected "); } buf.append(" >" + key + "</option>"); buf.append("\r\n"); } buf.append("</select>"); } try { this.pageContext.getOut().write(buf.toString()); } catch (IOException e) { throw new JspException(e); } name = null; dbTable = null; valueCol = null; nameCol = null; if(paramMap != null ) { paramMap.clear(); } return EVAL_PAGE; } @Override public int doStartTag() throws JspException { return super.doStartTag(); } }
如果自定义标签要实现数据的动态变化,必须实现DynamicAttributes接口,重写setDynamicAttribute方法。该类的所有属性除了paramMap是作为从后台传递菜单内容到前端的数据载体外,其他属性都是标签定义的。
我还特地实现了一个数据处理类,代码如下:
package com.vness.data; import java.sql.ResultSet; import java.util.HashMap; import com.vness.tool.dbTool; public class pullDownMenuData{ private HashMap<String, String> data; public void selectData(String sql) throws Exception{ dbTool dt= new dbTool(); dt.createConnection(); ResultSet rs = dt.executeSQL(sql); data=new HashMap<String, String>(); while(rs.next()){ String name = rs.getString(1) ; String value = rs.getString(2) ; data.put(name, value); } } public HashMap<String, String> getData(){ return data; } }
整个类很简单,就是把数据从后台读取出来,放到map中,传递给标签类。
另外,还有一个数据库工具类,因为时间原因,实现的很简单,只实现了简单的连接、查询等功能。由于我实现的这个功能是内部的一个平台,不对外开发,并发量不大,所以也没用连接池,仅仅用了最简单的jdbc。如果并发高的话,建议使用别的方式实现。
package com.vness.tool; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Properties; public class dbTool { private Connection con; private ResultSet result; private static String url ; private static String username ; private static String password ; static{ try{ //加载MySql的驱动类 Class.forName("oracle.jdbc.driver.OracleDriver") ; }catch(ClassNotFoundException e){ e.printStackTrace() ; } try { loadInit() ; } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } private static void loadInit() throws Exception{ Properties prop = new Properties(); FileInputStream fis; fis = new FileInputStream("dbprop.properties"); prop.load(fis); url=prop.getProperty("url"); username=prop.getProperty("username"); password=prop.getProperty("password"); } public Connection createConnection() throws Exception{ if(url==null||username==null||password==null){ throw new Exception("database param is error!"); } con = DriverManager.getConnection(url , username , password ) ; return con; } public void closeConnection(){ if(con!=null){ try { con.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public ResultSet executeSQL(String sql){ try { Statement stmt=con.createStatement(); result = stmt.executeQuery(sql) ; } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } return result; } public static void main (String[] x) throws Exception { dbTool dt= new dbTool(); Connection con=dt.createConnection(); ResultSet rs = dt.executeSQL("select api_id,api_cnm from mpoptapii "); try { while(rs.next()){ String name = rs.getString(1) ; String pass = rs.getString(2) ; } } catch (SQLException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } dt.closeConnection(); } }
二、标签使用的配置
最后是需要配置了,配置完了就可有使用标签了。配置主要包括三个方面:标签的定义声明、web.xml的声明和页面的引用。
hitag.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>2.2.3</tlib-version> <jsp-version>1.2</jsp-version> <short-name>test</short-name> <tag> <name>hiselect</name> <tag-class>com.vness.mytag.tagSelectExt</tag-class> <dynamic-attributes>true</dynamic-attributes> </tag> </taglib>
web.xml:声明标签,在web.xml的最后加入如下配置。
<taglib> <taglib-uri>/WEB-INF/tlds/hitag.tld</taglib-uri> <taglib-location>/WEB-INF/tlds/hitag.tld</taglib-location> </taglib>
最后,就是页面的引入了。
<%@ page language="java" contentType="text/html; charset=GBK" pageEncoding="GBK"%> <%@ taglib uri="/WEB-INF/tlds/hitag.tld" prefix="test" %> <html> <head> <script type="text/javascript"> </script> </head> <body> <tr><td>接口名称</td><td><test:hiselect name="tstNm" id="tst_nm" optStyle="1" dbTable="mpoptapii" valueCol="api_id" nameCol="api_cnm" defaultSelected="1"/> </td></tr></body></html>