??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲精品国产国语,在线亚洲精品自拍,亚洲福利视频一区http://www.tkk7.com/zphab/category/41731.htmlzh-cnSat, 19 Sep 2009 04:58:26 GMTSat, 19 Sep 2009 04:58:26 GMT60Apache Common BeanUtilshttp://www.tkk7.com/zphab/articles/295632.html张^?/dc:creator>张^?/author>Fri, 18 Sep 2009 16:16:00 GMThttp://www.tkk7.com/zphab/articles/295632.htmlhttp://www.tkk7.com/zphab/comments/295632.htmlhttp://www.tkk7.com/zphab/articles/295632.html#Feedback0http://www.tkk7.com/zphab/comments/commentRss/295632.htmlhttp://www.tkk7.com/zphab/services/trackbacks/295632.html目前 Commons ?/strong>
     目前已经开发有 release 出来的版本有 BeanUtils, Betwixt, CLI, Collections, DBCP, Digester, Discovery, EL, FileUpload, HttpClient, Jelly, Jexl, JXPath, Lang, Latka, Logging, Modeler, Net, Pool, Validator {等 

     每个版本都不太一? 随时都有更新的可? 至于q没?release 出来正式的版? 有一些项? 可能也正?使用?!! 也是有可能因为其他项目做出来的一些元? 可以抽出来共用的, 例如目前 struts 用的 Resources ( Resource bundle component ) , 也被列入 SandBox 研发? 准备 release 更符合所有项目的 lg. 

     jakarta Z要有 commons q个 project 出现, 是希望大家不用重复开发一L(fng)lg, 辑ֈ reusable ?目的 !! 而且他们都有Ҏ(gu)使用的特? 也是各个 jakarta committer 牛h们的_֍C, 因此, l对不能?q这一?open source project !! 各位亲爱?java 同胞(yu)?.................

BeanUtils 介绍
     当我在选择要先介绍哪一个组? 实在犹U?jin)很? 因ؓ(f)每一个实在都是精? 久久无法做出军_, 所以呢, 只好按照是否 release 再按照字母的先后, 做一个排? 希望大家明白 ....

所?BeanUtils Z要开发呢, 每个工程师或许在?JavaBean 的时? 都会(x)乖乖地去?getters ?setters, 是 getXXX() ?setXXX() methods, 但是当你?object 是动态生的, 也许是用文g, 也许?其他原因, 那你该如何去存取数据?!! 

     几个例子你可能会(x)用到 BeanUtils, 当然, q是已经存在的项目了(jin)

     你大可以使用 java api 中的 java.lang.reflect ?java.beans 来达到这些数据交?~~ 不过? 隑ֺ有点 ?=.="" ,但是, BeanUtils 会(x)减低你开发的旉 !! 

     目前最新的版本?1.6.1 (2003/2/18 released), 下蝲位置?Binary & Source

BeanUtils API 介绍
     BeanUtils ?Java API 主要?package d四项

  1. org.apache.commons.beanutils
  2. org.apache.commons.beanutils.converters
  3. org.apache.commons.beanutils.locale
  4. org.apache.commons.beanutils.locale.converters
     其实除了(jin)W一之? 其他的都是后来的版本才加上去? converters 是专门处理不同传入?object 该如 何{? locale ? 是Z(jin)国际化的处理, 所以重Ҏ(gu)都会(x)摆在W一?!

     而其中最常用到的 class ?PropertyUtils ?ConvertUtils q有 DynaBeans( 有用 struts dynaform 的应 该不陌生 )


BeanUtils.PropertyUtils 介绍

     基本? 我假讑֤家对 JavaBean 的开发都没有问题, 是?getters ?setters 都了(jin)解是什? 先假? Employee class 
    public class Employee {
        public Address getAddress(String type);
        public void setAddress(String type, Address address);
        public Employee getSubordinate(int index);
        public void setSubordinate(int index, Employee subordinate);
        public String getFirstName();
        public void setFirstName(String firstName);
        public String getLastName();
        public void setLastName(String lastName);
    }

     ?PropertyUtils 中会(x)区分ZU?method 状?br />
  • Simple - 如果你是用到 primitive 语法, ?int, String 或其他自行开发的 objects {等, 只需要单一的对象就可以取得数据

    PropertyUtils.getSimpleProperty(Object bean, String name)
    PropertyUtils.setSimpleProperty(Object bean, String name, Object value) 

  • Employee employee = ...;
    String firstName = (String)PropertyUtils.getSimpleProperty(employee, "firstName");
    String lastName = (String)PropertyUtils.getSimpleProperty(employee, "lastName");
    .............
    PropertyUtils.setSimpleProperty(employee, "firstName", firstName);
    PropertyUtils.setSimpleProperty(employee, "lastName", lastName);
     
  • Indexed - 如果你是用到 Collection ?List 实作出来?objects , 只需要用一?index 数值就可以取得对象的状?br />
    PropertyUtils.getIndexedProperty(Object bean, String name)
    PropertyUtils.getIndexedProperty(Object bean, String name, int index)
    PropertyUtils.setIndexedProperty(Object bean, String name, Object value)
    PropertyUtils.setIndexedProperty(Object bean, String name, int index, Object value) 


    Employee employee = ...;
    int index = ...;
    String name = "subordinate[" + index + "]";
    Employee subordinate = (Employee)PropertyUtils.getIndexedProperty(employee, name);
    Employee employee = ...;
    int index = ...;
    Employee subordinate = (Employee)PropertyUtils.getIndexedProperty(employee, "subordinate", index);

         
  • Mapped - 如果你是用到 Map 延Z?objects , 只需要用一?key 值就可以?得数?br />
    PropertyUtils.getMappedProperty(Object bean, String name)
    PropertyUtils.getMappedProperty(Object bean, String name, String key)
    PropertyUtils.setMappedProperty(Object bean, String name, Object value)
    PropertyUtils.setMappedProperty(Object bean, String name, String key, Object value) 


    Employee employee = ...;
    Address address = ...;
    PropertyUtils.setMappedProperty(employee, "address(home)", address);
    Employee employee = ...;
    Address address = ...;
    PropertyUtils.setMappedProperty(employee, "address", "home", address);   
     但是如果你是巢状(nested)的数据结? 你该如何取得你要的数据呢

          PropertyUtils.getNestedProperty(Object bean, String name) 
          PropertyUtils.setNestedProperty(Object bean, String name, Object value) 

     你只需要简单地使用 ".", 可以得C要的数据?
     String city = (String)PropertyUtils.getNestedProperty(employee, "address(home).city");
     千万要记? BeanUtils 是要让你随心(j)所Ʋ? 所以呢 index , mapped 当然都可以这样?nbsp;
     Employee employee = ...;
     String city = (String) PropertyUtils.getProperty(employee, "subordinate[3].address(home).city");

BeanUtils.DynaBean and BeanUtils.DynaClass 介绍
     所有的 Dynamic JavaBean 都是实现 DynaBean ?DynaClass q两?interface, 也可能会(x)用到 DynaProperty class 来存?properties . 我们Z要用?Dynamic JavaBean ? 例如, 你从数据库取出来 的数? 有时候可能是三个栏位, 有时候是四个栏位, 如果我们对于每个 Bean 都要d一?class, ׃(x)?? 所以对于每一U?javabean 我们p定他的属性有哪些, 接着可以?PropertyUtils 来将他的数值取 ? 如此, 可以减少很多开发工? ?Struts 的课E中, 很多人问到我, 请问每一?ActionForm 都必d ?java 文g? 当然, 不需要的, 否则一个网一?ActionForm ( 假设都不一?), 那么, q么费旉 的工? Zq要使用 Struts 来作?Framework ? 所以我们都是?org.apache.struts.action.DynaActionForm!!

MutableDynaClass ( since $1.5 ) q是蛮新的一?DynaClass, 是ؓ(f)?jin)动态可以调?properties !

  • BasicDynaBean and BasicDynaClass - 基本?Dynamic cd

    BasicDynaClass(java.lang.String name, java.lang.Class dynaBeanClass, DynaProperty[] properties)
    BasicDynaBean(DynaClass dynaClass) 


    DynaProperty[] props = new DynaProperty[]{
        new DynaProperty("address", java.util.Map.class),
        new DynaProperty("subordinate", mypackage.Employee[].class),
        new DynaProperty("firstName", String.class),
        new DynaProperty("lastName",  String.class)
    };
    BasicDynaClass dynaClass = new BasicDynaClass("employee", null, props);
    DynaBean employee = dynaClass.newInstance();
    employee.set("address", new HashMap());
    employee.set("subordinate", new mypackage.Employee[0]);
    employee.set("firstName", "Fred");
    employee.set("lastName", "Flintstone");

         
  • ResultSetDynaClass (Wraps ResultSet in DynaBeans) - 使用 ResultSet ?Dynamic JavaBean

    ResultSetDynaClass(java.sql.ResultSet resultSet)
    ResultSetDynaClass(java.sql.ResultSet resultSet, boolean lowerCase)

    如果 lowerCase 设ؓ(f) false , q回的数据栏位名根?JDBC q回的ؓ(f)? default ?true. 

    Connection conn = ...;
    Statement stmt = conn.createStatement();
    ResultSet rs = stmt.executeQuery("select account_id, name from customers");
    Iterator rows = (new ResultSetDynaClass(rs)).iterator();
    while (rows.hasNext()) {
        DynaBean row = (DynaBean) rows.next();
        System.out.println("Account number is " + row.get("account_id") + " and name is " + row.get("name"));
    }
    rs.close();
    stmt.close();

         
  • RowSetDynaClass (Disconnected ResultSet as DynaBeans) - 使用 RowSet ?Dynamic JavaBean

    RowSetDynaClass(java.sql.ResultSet resultSet)
    RowSetDynaClass(java.sql.ResultSet resultSet, boolean lowerCase)

    如果 lowerCase 设ؓ(f) false , q回的数据栏位名根?JDBC q回的ؓ(f)? default ?true. 

    Connection conn = ...;  // Acquire connection from pool
    Statement stmt = conn.createStatement();
    ResultSet rs = stmt.executeQuery("SELECT ...");
    RowSetDynaClass rsdc = new RowSetDynaClass(rs);
    rs.close();
    stmt.close();
    ...;                    // Return connection to pool
    List rows = rsdc.getRows();
    ...;                   // Process the rows as desired  

         
  • WrapDynaBean and WrapDynaClass - 包装过?Dynamic JavaBean

    如果你对?DynaBean 的功能强? 非常佩服的同? 手边?JavaBean 又不能随随便便就不用 ?你就把他包装h ....

    WrapDynaClass(java.lang.Class beanClass)
    WrapDynaBean(java.lang.Object instance)
    ConvertingWrapDynaBean(java.lang.Object instance)

    MyBean bean = ...;
    DynaBean wrapper = new WrapDynaBean(bean);
    String firstName = wrapper.get("firstName");  

BeanUtils.ConvertUtils 介绍
          在很多情? 例如 struts framework ? 常常用?request.getParameter 的参? 需要{换成 正确的数据类? 所?ConvertUtils 是来处理这些动?

          ConvertUtils().convert(java.lang.Object value) 
          ConvertUtils().convert(java.lang.String[] values, java.lang.Class clazz) 
          ConvertUtils().convert(java.lang.String value, java.lang.Class clazz) 

     HttpServletRequest request = ...;
     MyBean bean = ...;
     HashMap map = new HashMap();
     Enumeration names = request.getParameterNames();
     while (names.hasMoreElements()) {
          String name = (String) names.nextElement();
          map.put(name, request.getParameterValues(name));
     }
     BeanUtils.populate(bean, map);// it will use ConvertUtils for convertings

 

     目前支持的类型有

  • sjava.lang.BigDecimal
  • java.lang.BigInteger
  • boolean and java.lang.Boolean
  • byte and java.lang.Byte
  • char and java.lang.Character
  • java.lang.Class
  • double and java.lang.Double
  • float and java.lang.Float
  • int and java.lang.Integer
  • long and java.lang.Long
  • short and java.lang.Short
  • java.lang.String
  • java.sql.Date
  • java.sql.Time
  • java.sql.Timestamp
     也可以徏立自q converter 

   Converter myConverter = new org.apache.commons.beanutils.converter.IntegerConverter(); 
   ConvertUtils.register(myConverter, Integer.TYPE);    // Native type 
   ConvertUtils.register(myConverter, Integer.class);   // Wrapper class


]]>
?rn)态化面http://www.tkk7.com/zphab/articles/295631.html张^?/dc:creator>张^?/author>Fri, 18 Sep 2009 16:06:00 GMThttp://www.tkk7.com/zphab/articles/295631.htmlhttp://www.tkk7.com/zphab/comments/295631.htmlhttp://www.tkk7.com/zphab/articles/295631.html#Feedback0http://www.tkk7.com/zphab/comments/commentRss/295631.htmlhttp://www.tkk7.com/zphab/services/trackbacks/295631.htmlpackage com.zph.util;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.nio.charset.Charset;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

/**
 * @author shaevel
 * 该方法只能静(rn)态化本应用的动态页?br />  *
 */
public class TestToHtml extends HttpServlet {
 private static final long serialVersionUID = -8637885029101603118L;
 public void doGet(HttpServletRequest request, HttpServletResponse response)
   throws IOException, ServletException {
  
  Charset cs = Charset.forName("UTF-8");  //讄生成文g的字W集
  
  String url = "";
  String name = "";
  ServletContext sc = getServletContext();
  String file_name = request.getParameter("file_name");// 你要讉K的jsp文g,如index.jsp
  // 则你讉Kq个servlet时加参数.?a href="http://localhost/toHtml?file_name=index">http://localhost/toHtml?file_name=index
  url = "/" + file_name + ".jsp?id=zhang&m=13425109339";// q是你要生成wml的jsp文g
  name = "E://1.wml";// q是生成的wml文g??,如index.wml.
  RequestDispatcher rd = sc.getRequestDispatcher(url);
  final ByteArrayOutputStream os = new ByteArrayOutputStream();
  final ServletOutputStream stream = new ServletOutputStream() {
   public void write(byte[] data, int offset, int length) {
    os.write(data, offset, length);
   }
   public void write(int b) throws IOException {
    os.write(b);
   }
  };
  final PrintWriter pw = new PrintWriter(new OutputStreamWriter(os,cs));
  HttpServletResponse rep = new HttpServletResponseWrapper(response) {
   public ServletOutputStream getOutputStream() {
    return stream;
   }
   public PrintWriter getWriter() {
    return pw;
   }
  };
  rd.include(request, rep);
  pw.flush();
  FileOutputStream fos = new FileOutputStream(name); // 把jsp输出的内容写到xxx.wml
  os.writeTo(fos);
  fos.close();
  PrintWriter out = response.getWriter();
  out.print("<p align=center><font size=3 color=red>successfully??</font></p>");
 }
 public void doPost(HttpServletRequest request, HttpServletResponse response)
   throws IOException, ServletException {
  doGet(request, response);
 }
}

]]>
Map Cachehttp://www.tkk7.com/zphab/articles/295630.html张^?/dc:creator>张^?/author>Fri, 18 Sep 2009 16:04:00 GMThttp://www.tkk7.com/zphab/articles/295630.htmlhttp://www.tkk7.com/zphab/comments/295630.htmlhttp://www.tkk7.com/zphab/articles/295630.html#Feedback0http://www.tkk7.com/zphab/comments/commentRss/295630.htmlhttp://www.tkk7.com/zphab/services/trackbacks/295630.htmlpackage com.zph.util;
import java.util.HashMap;
import java.util.Map;
/**
 * @author shaevel
 *
 */
public class MapUtil {

 public static Map<String, Object> Map_Info = new HashMap<String,Object>();
 
 public static void addObject(String id, Object o){
  Map_Info.put(id, o);
  System.out.println("============== size: " + Map_Info.size() + " ================");
 }
 
 public static void moveObject(String id){
  if(Map_Info.get(id) != null){
   Map_Info.remove(id);
  }
 }
 
 public static Object getObject(String id){
  if(Map_Info.get(id) != null){
   return Map_Info.get(id);
  }else{
   return "";
  }
 }
}


]]>
dExcel文ghttp://www.tkk7.com/zphab/articles/295629.html张^?/dc:creator>张^?/author>Fri, 18 Sep 2009 16:02:00 GMThttp://www.tkk7.com/zphab/articles/295629.htmlhttp://www.tkk7.com/zphab/comments/295629.htmlhttp://www.tkk7.com/zphab/articles/295629.html#Feedback0http://www.tkk7.com/zphab/comments/commentRss/295629.htmlhttp://www.tkk7.com/zphab/services/trackbacks/295629.htmlpackage com.zph.util;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;

/**
 * @author shaevel
 *
 */
public class ReadExcel {

 //public static String outputFile="D:\\JTest\\gongye.xls";

 /**
 * @param args
 */
 public static void main(String[] args) {

  String outputFile="D:\\gongye.xls";
  createXLS(outputFile);
  //String inputFile = "D:\\shuaka.xls";
  //readXLS(inputFile);
 }

 public static void createXLS(String outputFile){

  try{

   // 创徏新的Excel 工作?br />    HSSFWorkbook workbook = new HSSFWorkbook();

   // 在Excel工作中Z工作表,其名为缺省?br />    // 如要新徏一名ؓ(f)"效益指标"的工作表Q其语句为:(x)
   // HSSFSheet sheet = workbook.createSheet("效益指标");
   HSSFSheet sheet = workbook.createSheet();

   // 在烦(ch)?的位|创Q最端的行Q?br />    HSSFRow row = sheet.createRow((short)0);

   //在烦(ch)?的位|创建单元格Q左上端Q?br />    HSSFCell cell = row.createCell((short) 0);

   // 定义单元gؓ(f)字符串类?br />    cell.setCellType(HSSFCell.CELL_TYPE_STRING);
   cell.setEncoding(HSSFCell.ENCODING_UTF_16);

   // 在单元格中输入一些内?br />    cell.setCellValue("我们的故?);

   // 新徏一输出文g?br />    FileOutputStream fOut = new FileOutputStream(outputFile);

   // 把相应的Excel 工作存?br />    workbook.write(fOut);
   fOut.flush();

   // 操作l束Q关闭文?br />    fOut.close();

   System.out.println("文g生成...");
  }catch(Exception e) {
   System.out.println("已运?xlCreate() : " + e );
  }
 }

 public static void readXLS(String inputFile){

  try{

   // 创徏对Excel工作文件的引用
   HSSFWorkbook workbook = new HSSFWorkbook(new FileInputStream(inputFile));

   // 创徏对工作表的引用?br />    // 本例是按名引用(让我们假定那张表有着~省?Sheet1"Q?br />    HSSFSheet sheet = workbook.getSheet("Sheet1");

   // 也可用getSheetAt(int index)按烦(ch)引引用,
   // 在Excel文档中,W一张工作表的缺省烦(ch)引是0Q?br />    // 其语句ؓ(f)QHSSFSheet sheet = workbook.getSheetAt(0);
   // d左上端单?br />    for(int i = 0; i < 8; i++){
    for(int j =0; j < 6; j++){
     HSSFRow row = sheet.getRow(i);
     HSSFCell cell = row.getCell((short)j);

     // 输出单元内容Qcell.getStringCellValue()是取所在单元的?br />      if(cell.getCellType() == 0){
      System.out.print(cell.getNumericCellValue() + "  ");
     }
     if(cell.getCellType() == 1){
      System.out.print(cell.getStringCellValue() + "  ");
     }
    }
   System.out.print("\n");
   }
  }catch(Exception e) {
   System.out.println("已运行xlRead() : " + e );
  }
 }
}



]]>
Hibernate与JdbcTemplate׃n事务理http://www.tkk7.com/zphab/articles/295627.html张^?/dc:creator>张^?/author>Fri, 18 Sep 2009 15:51:00 GMThttp://www.tkk7.com/zphab/articles/295627.htmlhttp://www.tkk7.com/zphab/comments/295627.htmlhttp://www.tkk7.com/zphab/articles/295627.html#Feedback0http://www.tkk7.com/zphab/comments/commentRss/295627.htmlhttp://www.tkk7.com/zphab/services/trackbacks/295627.html     在Spring和Hibernate的配|文件中Q我们可以对cM的方法进行事务控Ӟ也就是说某个Ҏ(gu)中含有多个数据库的写操作Q我们可以通过创徏一个Spring中的HibernateTransactionManager实例Q把相应的sessionFactory注入到其的sessionFactory属性中Q由事务声明的方式进行事务控制。样例如下:(x)

     <bean id="oaTM" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
          <property name="sessionFactory"><ref bean="oaSessionFactory"/></property>
     </bean>

     但是q种方式有个局限性,如果该方法中既有调用Hibernateq行存储Q也有通过JdbcTemplateq行数据库的写操作,如果在方法执行过E中Q写数据发生异常Ӟ只有U_?jin)事务管理的通过Hibernateq行存储的数据才?x)回滚,而通过JdbcTemplate方式q行操作的数据不?x)进行回滚?/p>

     原因是Hibernate与JdbcTemplate使用的是不同DBConnectionQ而且JdbcTemplate未申明相应的事务理Q所以要惛_既用了(jin)HibernateQ也使用?jin)JdbcTemplateq行数据库存储操作的Ҏ(gu)q行事务理Q需要在Spring的配|文件做适当的修改,样例如下Q?nbsp;

     <bean id="oaTM" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
          <property name="sessionFactory"><ref bean="oaSessionFactory"/></property>
          <property name="dataSource"><ref bean="oaDataSource"/></property>
     </bean>

     JdbcTemplate和Hibernate能被wrap到同一个事务里。成立需要几Ҏ(gu)Ӟ(x)
     1、用同一个datasourceQ?br />      2、事务交由HibernateTransactionManager理Q?br />      3、相关dao以及(qing)service需要用runtime exception体系Q用spring提供的exception可以Q自己封装设计的runtime exception体系也行?



]]>
JAVA生成文ghttp://www.tkk7.com/zphab/articles/295623.html张^?/dc:creator>张^?/author>Fri, 18 Sep 2009 15:42:00 GMThttp://www.tkk7.com/zphab/articles/295623.htmlhttp://www.tkk7.com/zphab/comments/295623.htmlhttp://www.tkk7.com/zphab/articles/295623.html#Feedback0http://www.tkk7.com/zphab/comments/commentRss/295623.htmlhttp://www.tkk7.com/zphab/services/trackbacks/295623.htmlpackage com.zph.test;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;

/**
 * @author pinghui.zhang
 *
 */
public class StringToFile {
 
    /**
    * 把字W串写入文本?br />     * @param fileName 生成的文件绝对\?br />     * @param content 文g要保存的内容
    * @param enc  文g~码
    * @return
    */
    public static boolean writeStringToFile(String fileName,String content,String enc) {
        File file = new File(fileName);
        
        try {
            if(file.isFile()){
                file.deleteOnExit();
                file = new File(file.getAbsolutePath());
            }
            OutputStreamWriter os = null;
            if(enc==null||enc.length()==0){
                os = new OutputStreamWriter(new FileOutputStream(file));
            }else{
                os = new OutputStreamWriter(new FileOutputStream(file),enc);
            }
            os.write(content);
            os.close();
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
 
    public static void main(String args[]){
        int[] ids = {995, 996, 997};
        StringBuffer presb = new StringBuffer();
        StringBuffer sufsb = new StringBuffer();
        presb.append("<%@ page language=\"java\" import=\"java.util.*\" pageEncoding=\"UTF-8\"%>\n")
                .append("<%@ taglib uri=\"                 .append("<%\n")
                .append("\tString deptid = \"");
  
        sufsb.append("\"; //只要修改此处卛_\n")
                .append("\trequest.setAttribute(\"dept\", com.dadi.oa.system.DepartmentUtil.getDepartmentInfo(new Long(deptid)));\n")
                .append("\tString fromurl = request.getRequestURI().substring(request.getRequestURI().lastIndexOf(\"/\") + 1);\n")
                .append("%>\n")
                .append("<%@ include file=\"body.jsp\"%>");
  
        String content = "";
        String fileName = "";
  
        for(int i = 0; i < ids.length; i++){
            fileName = "D:\\project1\\OA\\Code\\jsp\\anth\\" + ids[i] + ".jsp";
            content = presb.toString() + ids[i] + sufsb.toString();
            writeStringToFile(fileName, content, "UTF-8");
        }
    }

}



]]>
使用 Java 开源工具徏立一个灵zȝ搜烦(ch)引擎【{摘?/title><link>http://www.tkk7.com/zphab/articles/295622.html</link><dc:creator>张^?/dc:creator><author>张^?/author><pubDate>Fri, 18 Sep 2009 15:39:00 GMT</pubDate><guid>http://www.tkk7.com/zphab/articles/295622.html</guid><wfw:comment>http://www.tkk7.com/zphab/comments/295622.html</wfw:comment><comments>http://www.tkk7.com/zphab/articles/295622.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/zphab/comments/commentRss/295622.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/zphab/services/trackbacks/295622.html</trackback:ping><description><![CDATA[<p><a cmimpressionsent="1"><font color="#5c81a7">??/font></a> (<a href="mailto:qiuyin04@software.nju.edu.cn?subject=使用 Java 开源工具徏立一个灵zȝ搜烦(ch)引擎&cc=zoucl@cn.ibm.com" cmimpressionsent="1"><font color="#5c81a7">qiuyin04@software.nju.edu.cn</font></a>)南京大学<br /> </p> <p>2007 q?11 ?27 ?/p> <blockquote>为应用程序添加搜索能力经常是一个常见的需求。本文介l了(jin)一个框Ӟ开发者可以用它以最的付出实现搜烦(ch)引擎功能Q理x(chng)况下只需要一个配|文件。该框架Z若干开源的库和工具Q如 Apache LuceneQSpring 框架Qcpdetector {。它支持多种资源。其中两个典型的例子是数据库资源和文件系l资源。Indexer 寚w|的资源q行索引q传输到中央服务器,之后q些索引可以通过 API q行搜烦(ch)。Spring 风格的配|文件允许清晰灵zȝ自定义和调整。核?API 也提供了(jin)可扩展的接口?</blockquote> <p><a><span><strong><font size="5">引言</font></strong></span></a></p> <p>       为应用程序添加搜索能力经常是一个常见的需求。尽已l有若干E序库提供了(jin)Ҏ(gu)索基设施的支持,然而对于很多h而言Q用它们从头开始徏立一个搜索引擎将是一个付Z而且可能乏味的过E。另一斚wQ很多的型应用对于搜烦(ch)功能的需求和应用场景h很大的相似性。本文试图以对多数小型应用的适用性ؓ(f)出发点,?Java 语言构徏一个灵zȝ搜烦(ch)引擎框架。用这个框Ӟ多数情Ş下可以以最的付出建立起一个搜索引擎。最理想的情况下Q甚臛_需要一个配|文件。特D的情Ş下,可以通过灉|地对框架q行扩展满需求。当?dng)如题所qͼq都是借助开源工L(fng)力量?</p> <p><br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td><img title="使用 Java 开源工具徏立一个灵zȝ搜烦(ch)引擎【{摘?- 大漠落日 - Ҏ(gu)明志 宁静(rn)致远 从容淡定 宠i不惊" height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br /> <img title="使用 Java 开源工具徏立一个灵zȝ搜烦(ch)引擎【{摘?- 大漠落日 - Ҏ(gu)明志 宁静(rn)致远 从容淡定 宠i不惊" height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td> </tr> </tbody> </table> <br /> <br /> </p> <p><a><span><strong><font size="5">基础知识</font></strong></span></a></p> <p>        Apache Lucene 是开发搜索类应用E序时最常用?Java cdQ我们的框架也将Z它。ؓ(f)?jin)下文更好的描述Q我们需要先?jin)解一些有?Lucene 和搜索的基础知识。注意,本文不关注烦(ch)引的文g格式、分词技术等话题?</p> <p><a><span><strong><font size="3">什么是搜烦(ch)和烦(ch)?/font></strong></span></a></p> <p>        从用L(fng)角度来看Q搜索的q程是通过关键字在某种资源中寻扄定的内容的过E。而从计算机的角度来看Q实现这个过E可以有两种办法。一是对所有资源逐个与关键字匚wQ返回所有满_配的内容Q二是如同字怸样事先徏立一个对应表Q把关键字与资源的内容对应v来,搜烦(ch)时直接查找这个表卛_。显而易见,W二个办法效率要高得多。徏立这个对应表事实上就是徏立逆向索引Qinverted indexQ的q程?</p> <p><a><span><strong><font size="3">Lucene 基本概念</font></strong></span></a></p> <p>        Lucene ?Doug Cutting ?Java 开发的用于全文搜烦(ch)的工具库。在q里Q我假设读者对其已有基本的?jin)解Q我们只对一些重要的概念要介l。要深入?jin)解可以参?<a cmimpressionsent="1"><font color="#5c81a7">参考资?/font></a> 中列出的相关文章和图书。下面这些是 Lucene 里比较重要的cR?</p> <ul> <li><co<wbr>DE><font face="Courier" size="2">Document</font></co<wbr>DE>Q烦(ch)引包含多?<co<wbr>DE><font face="Courier" size="2">Document</font></co<wbr>DE>。而每?<co<wbr>DE><font face="Courier" size="2">Document</font></co<wbr>DE> 则包含多?<co<wbr>DE><font face="Courier" size="2">Field</font></co<wbr>DE> 对象?co<wbr>DE><font face="Courier" size="2">Document</font></co<wbr>DE> 可以是从数据库表里取出的一堆数据,可以是一个文Ӟ也可以是一个网늭。注意,它不{同于文件系l中的文件? <li><co<wbr>DE><font face="Courier" size="2">Field</font></co<wbr>DE>Q一?<co<wbr>DE><font face="Courier" size="2">Field</font></co<wbr>DE> 有一个名Uͼ它对?<co<wbr>DE><font face="Courier" size="2">Document</font></co<wbr>DE>的一部分数据Q表C文档的内容或者文档的元数据(与下文中提到的资源元数据不是一个概念)(j)。一?<co<wbr>DE><font face="Courier" size="2">Field</font></co<wbr>DE> 对象有两个重要属性:(x)Store ( 可以?YES, NO, COMPACT 三种取?) ?Index ( 可以?TOKENIZED, UN_TOKENIZED, NO, NO_NORMS 四种取?) <li><co<wbr>DE><font face="Courier" size="2">Query</font></co<wbr>DE>Q抽象了(jin)搜烦(ch)时用的语句? <li><co<wbr>DE><font face="Courier" size="2">IndexSearcher</font></co<wbr>DE>Q提?<co<wbr>DE><font face="Courier" size="2">Query</font></co<wbr>DE> 对象l它Q它利用已有的烦(ch)引进行搜索ƈq回搜烦(ch)l果? <li><co<wbr>DE><font face="Courier" size="2">Hits</font></co<wbr>DE>Q一个容器,包含?jin)指?em>一部分</em>搜烦(ch)l果的指针?</li> </ul> <p>        使用 Lucene 来进行编制烦(ch)引的q程大致为:(x)输入的数据源统一为字W串或者文本流的Ş式,然后从数据源提取数据Q创建合适的 <co<wbr>DE><font face="Courier" size="2">Field</font></co<wbr>DE> d到对应数据源?<co<wbr>DE><font face="Courier" size="2">Document</font></co<wbr>DE> 对象之中?<br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td><img title="使用 Java 开源工具徏立一个灵zȝ搜烦(ch)引擎【{摘?- 大漠落日 - Ҏ(gu)明志 宁静(rn)致远 从容淡定 宠i不惊" height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br /> <img title="使用 Java 开源工具徏立一个灵zȝ搜烦(ch)引擎【{摘?- 大漠落日 - Ҏ(gu)明志 宁静(rn)致远 从容淡定 宠i不惊" height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td> </tr> </tbody> </table> <br /> <br /> </p> <p><a><span><strong><font size="5">pȝ概览</font></strong></span></a></p> <p>        要徏立一个通用的框Ӟ必须对不同情늚共性进行抽象。反映到设计需要注意两炏V一是要提供扩展接口Q二是要量降低模块之间的耦合E度。我们的框架很简单地分ؓ(f)两个模块Q烦(ch)引模块和搜烦(ch)模块。烦(ch)引模块在不同的机器上各自q行对资源的索引Qƈ把烦(ch)引文Ӟ事实上,下面我们?x)说刎ͼq有元数据)(j)l一传输到同一个地方(可以是在q程服务器上Q也可以是在本地Q。搜索模块则利用q些从多个烦(ch)引模块收集到的数据完成用L(fng)搜烦(ch)h?/p> <p><a cmimpressionsent="1"><font color="#5c81a7">        ?1</font></a> 展现?jin)整体的框架。可以看刎ͼ两个模块之间相对是独立的Q它们之间的兌不是通过代码Q而是通过索引和元数据。在下文中,我们会(x)详细介绍如何Z开源工兯计和实现q两个模块?/p> <p><br /> <a><strong>?1. pȝ架构?/strong></a><br /> <div align="center"><img title="使用 Java 开源工具徏立一个灵zȝ搜烦(ch)引擎【{摘?- 大漠落日 - Ҏ(gu)明志 宁静(rn)致远 从容淡定 宠i不惊" alt="?1. pȝ架构?" src="http://www.ibm.com/developerworks/cn/java/j-lo-sefrmk/arch.png" /></div> <br /> <br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td><img title="使用 Java 开源工具徏立一个灵zȝ搜烦(ch)引擎【{摘?- 大漠落日 - Ҏ(gu)明志 宁静(rn)致远 从容淡定 宠i不惊" height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br /> <img title="使用 Java 开源工具徏立一个灵zȝ搜烦(ch)引擎【{摘?- 大漠落日 - Ҏ(gu)明志 宁静(rn)致远 从容淡定 宠i不惊" height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td> </tr> </tbody> </table> <br /> <br /> <p> </p> <p><a><span><strong><font size="5">建立索引</font></strong></span></a></p> <p>        可以q行索引的对象有很多Q如文g、网c(din)RSS Feed {。在我们的框架中Q我们定义可以进行烦(ch)引的<strong>一c?/strong>对象?em>资源</em>。从实现l节上来_(d)从一个资源中可以提取出多?<co<wbr>DE><font face="Courier" size="2">Document</font></co<wbr>DE> 对象。文件系l资源和数据库结果集资源都是资源的代表性例子?/p> <p>        前面提到Q从资源中收集到的烦(ch)引被l一传送到同一个地方,以被搜烦(ch)模块所用。显焉?jin)?ch)引之外,搜烦(ch)模块需要对资源有更多的?jin)解Q如资源的名U、搜索该资源后搜索结果的呈现格式{。这些额外的附加信息UCؓ(f)资源?em>元数?/em>。元数据和烦(ch)引数据一同被攉hQ放|到某个特定的位|?/p> <p>        要地介绍q资源的概念之后Q我们首先ؓ(f)其定义一?<co<wbr>DE><font face="Courier" size="2">Resource</font></co<wbr>DE> 接口。这个接口的声明如下?/p> <p><br />     <a><strong>清单 1. Resource 接口</strong></a><br /> <table style="width: 951px; height: 183px" cellspacing="0" cellpadding="0" width="951" align="center" border="0"> <tbody> <tr> <td> <pre>public interface Resource { // RequestProcessor 对象被动C资源中提?DocumentQƈq回提取的数? public int extractDocuments(ResourceProcessor processor); // d?DocumentListener 在每一?Document 对象被提取出时被调用 public void addDocumentListener(DocumentListener l); // q回资源的元数据 public ResourceMetaData getMetaData(); }</pre> </td> </tr> </tbody> </table> <br /> </p> <p>        其中元数据包含的字段见下表。在下文中,我们q(sh)(x)对元数据的用途做更多的介l?/p> <p><br />         <a><strong>?1. 资源元数据包含的字段</strong></a><br /> <table style="width: 879px; height: 106px" cellspacing="0" cellpadding="0" width="879" align="center" border="0"> <tbody> <tr> <th scope="col">属?/th> <th scope="col">cd</th> <th scope="col">含义</th> </tr> <tr> <th scope="row"><a>resourceName</a> </th> <td>String</td> <td>资源?strong>唯一名称</strong> </td> </tr> <tr> <th scope="row">resourceDescription</th> <td>String</td> <td>资源的介l性文?/td> </tr> <tr> <th scope="row"><a>hitTextPattern</a> </th> <td>String</td> <td>当文档被搜烦(ch)到时Q这?pattern 规定?jin)结果显C的格式</td> </tr> <tr> <th scope="row"><a>searchableFields</a> </th> <td>String[]</td> <td>可以被搜索的字段名称</td> </tr> </tbody> </table> </p> <p>        ?<co<wbr>DE><font face="Courier" size="2">DocumentListener</font></co<wbr>DE> 的代码如下?/p> <p><br />     <a><strong>清单 2. DocumentListener 接口</strong></a><br /> <table style="width: 952px; height: 71px" cellspacing="0" cellpadding="0" width="952" align="center" border="0"> <tbody> <tr> <td> <pre>public interface DocumentListener extends EventListener { public void documentExtracted(Document doc); } </pre> </td> </tr> </tbody> </table> <br /> </p> <p>        Z(jin)让烦(ch)引模块能够知道所有需要被索引的资源,我们在这里?<a cmimpressionsent="1"><font color="#5c81a7">Spring</font></a> 风格?XML 文g配置索引模块中的所有组Ӟ其是所有资源。?zhn)可以?<a cmimpressionsent="1"><font color="#5c81a7">下蝲部分</font></a> 查看一个示例配|文件?/p> <p> <table cellspacing="0" cellpadding="0" width="40%" align="right" border="0"> <tbody> <tr> <td width="10"><img title="使用 Java 开源工具徏立一个灵zȝ搜烦(ch)引擎【{摘?- 大漠落日 - Ҏ(gu)明志 宁静(rn)致远 从容淡定 宠i不惊" height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" /></td> <td> <table cellspacing="0" cellpadding="5" width="100%" border="1"> <tbody> <tr> <td bgcolor="#eeeeee"><a><strong>Z么选择使用 Spring 风格的配|文Ӟ</strong></a><br /> <p>q主要有两个好处Q?</p> <ul> <li>仅依赖于 Spring Core ?Spring Beans 便免M(jin)定义配置机制和解析配|文件的负担Q? <li>Spring ?IoC 机制降低?jin)框架的耦合性,q扩展框架变得单; </li> </ul> <p> </p> </td> </tr> </tbody> </table> </td> </tr> </tbody> </table> </p> <p>        Z以上内容Q我们可以大致描q出索引模块工作的过E:(x)     </p> <ol> <li>首先?XML 配置?bean 中找出所?<co<wbr>DE><font face="Courier" size="2">Resource</font></co<wbr>DE> 对象Q? <li>Ҏ(gu)一个调用其 <co<wbr>DE><font face="Courier" size="2">extractDocuments()</font></co<wbr>DE> Ҏ(gu)Q这一步除?jin)完成对资源的?ch)引外Q还?sh)(x)在每次提取Z?<co<wbr>DE><font face="Courier" size="2">Document</font></co<wbr>DE> 对象之后Q通知注册在该资源上的所?<co<wbr>DE><font face="Courier" size="2">DocumentListener</font></co<wbr>DE>Q? <li>接着处理资源的元数据Q?co<wbr>DE><font face="Courier" size="2">getMetaData()</font></co<wbr>DE> 的返回|(j)Q? <li>缓存里的数据写入到本地盘或者传送给q程服务器; </li> </ol> <p> </p> <p>        在这个过E中Q有两个地方值得注意?/p> <p>        W一Q对资源可以注册 <co<wbr>DE><font face="Courier" size="2">DocumentListener</font></co<wbr>DE> 使得我们可以在运行时d索引q程有更为动态的控制。D一个简单例子,Ҏ(gu)个文章发布站点的文章q行索引Ӟ一个很正常的要求便是发布时间更靠近当前旉的文章需要在搜烦(ch)l果中排在靠前的位置。每文章显然对应一?<co<wbr>DE><font face="Courier" size="2">Document</font></co<wbr>DE> 对象Q在 Lucene 中我们可以通过讄 <co<wbr>DE><font face="Courier" size="2">Document</font></co<wbr>DE> ?<co<wbr>DE><font face="Courier" size="2">boost</font></co<wbr>DE> 值来对其q行加权。假讑օ中文章发布时间的 <co<wbr>DE><font face="Courier" size="2">Field</font></co<wbr>DE> 的名UCؓ(f) <co<wbr>DE><font face="Courier" size="2">PUB_TIME</font></co<wbr>DE>Q那么我们可以ؓ(f)资源注册一?<co<wbr>DE><font face="Courier" size="2">DocumentListener</font></co<wbr>DE>Q当它被通知Ӟ则检?<co<wbr>DE><font face="Courier" size="2">PUB_TIME</font></co<wbr>DE> 的|Ҏ(gu)距离当前旉的远q进行加权?/p> <p>        W二点很昄Q在q个q程中,<co<wbr>DE><font face="Courier" size="2">extractDocuments()</font></co<wbr>DE> Ҏ(gu)的实C不同cd的资源而各异。下面我们主要讨ZU类型的资源Q文件系l资源和数据库结果集资源。这两个c都实现?jin)上面?<co<wbr>DE><font face="Courier" size="2">接口</font></co<wbr>DE>?/p> <p><a><span><strong><font size="3">    文gpȝ资源</font></strong></span></a></p> <p>        Ҏ(gu)件系l资源的索引通常从一个基目录开始,递归处理每个需要进行烦(ch)引的文g。该资源有一个字W串数组cd?<co<wbr>DE><font face="Courier" size="2">excludedFiles</font></co<wbr>DE> 属性,表示在处理文件时需要排除的文gl对路径的正则表辑ּ。在递归遍历文gpȝ?wi)的同时Q绝对\径匹?<co<wbr>DE><font face="Courier" size="2">excludedFiles</font></co<wbr>DE> 中Q意一的文g不?x)被处理。这主要是考虑C般我们只需要对一部分文g夹(比如排除可能存在的备份目录)(j)中的一部分文gQ如 doc, ppt 文g{)(j)q行索引?/p> <p>        除了(jin)所有文件共有的文g名、文件\径、文件大和修改旉{?FieldQ不同类型的文g需要有不同的处理方法。ؓ(f)?jin)保留灵zL,我们使用 Strategy 模式装对不同类型文件的处理方式。ؓ(f)此我们抽象出一?<co<wbr>DE><font face="Courier" size="2">DocumentBuilder</font></co<wbr>DE> 的接口,该接口仅定义?jin)一个方法如下:(x)</p> <p><br />     <a><strong>清单 3. DocumentBuilder 接口</strong></a><br /> <table style="width: 951px; height: 71px" cellspacing="0" cellpadding="0" width="951" align="center" border="0"> <tbody> <tr> <td> <pre>public interface DocumentBuilder { Document buildDocument(InputStream is); }</pre> </td> </tr> </tbody> </table> <br /> <table style="width: 303px; height: 247px" cellspacing="0" cellpadding="0" width="303" align="right" border="0"> <tbody> <tr> <td width="10"><img title="使用 Java 开源工具徏立一个灵zȝ搜烦(ch)引擎【{摘?- 大漠落日 - Ҏ(gu)明志 宁静(rn)致远 从容淡定 宠i不惊" height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" /></td> <td> <table style="width: 227px; height: 224px" cellspacing="0" cellpadding="5" width="227" border="1"> <tbody> <tr> <td bgcolor="#eeeeee"><a><strong>什么是 Strategy 模式Q?/strong></a><br /> <p>Ҏ(gu) Design patterns: Elements of reusable object orientated software 一书:(x)Strategy 模式“定义一pd的算法,把它们分别封装v来,q且使它们相互可以替换。这个模式得算法可以独立于使用它的客户而变化?#8221;</p> </td> </tr> </tbody> </table> </td> </tr> </tbody> </table> </p> <p>        不同?<co<wbr>DE><font face="Courier" size="2">DocumentBuilder</font></co<wbr>DE>QStrategyQ?用于从一个输入流中读取数据,处理不同cd的文件。对于常见的文g格式来说Q都有合适的开源工具帮助进行解析。在下表中我们列举一些常见文件类型的解析办法?/p> <p> <table style="width: 680px; height: 202px" cellspacing="0" cellpadding="0" align="center" border="0"> <tbody> <tr> <th>文gcd</th> <th>常用扩展?/th> <th>可以使用的解析办?/th> </tr> <tr> <td>U文本文?/td> <td>txt</td> <td>无需cd解析</td> </tr> <tr> <td>RTF 文档</td> <td>rtf</td> <td>使用 <co<wbr>DE><font face="Courier" size="2">javax.swing.text.rtf.RTFEditorKit</font></co<wbr>DE> c?/td> </tr> <tr> <td>Word 文档Q非 OOXML 格式Q?/td> <td>doc</td> <td>Apache POI Q可配合使用 POI ScratchpadQ?/td> </tr> <tr> <td>PowerPoint 演示文稿Q非 OOXML 格式Q?/td> <td>xls</td> <td>Apache POI Q可配合使用 POI ScratchpadQ?/td> </tr> <tr> <td>PDF 文档</td> <td>pdf</td> <td>PDFBoxQ可能中文支持欠佻I(j)</td> </tr> <tr> <td>HTML 文档</td> <td>htm, html</td> <td>JTidy, Cobra</td> </tr> </tbody> </table> </p> <p>        q里?Word 文gZQ给Z个简单的参考实现?/p> <p><br />     <a><strong>清单 4. 解析U文本内容的实现</strong></a><br /> <table style="width: 941px; height: 327px" cellspacing="0" cellpadding="0" width="941" align="center" border="0"> <tbody> <tr> <td> <pre>// WordDocument ?Apache POI Scratchpad 中的一个类 Document buildDocument(InputStream is) { String bodyText = null; try { WordDocument wordDoc = new WordDocument(is); StringWriter sw = new StringWriter(); wordDoc.writeAllText(sw); sw.close(); bodyText = sw.toString(); } catch (Exception e) { throw new DocumentHandlerException("Cannot extract text from a Word document", e); } if ((bodyText != null) && (bodyText.trim().length() > 0)) { Document doc = new Document(); doc.add(new Field("body", bodyText, Field.Store.YES, Field.Index.TOKENIZED)); return doc; } return null; } </pre> </td> </tr> </tbody> </table> <br /> </p> <p>        那么如何选择合适的 Strategy 来处理文件呢QUNIX pȝ下的 file(1) 工具提供?jin)?<a cmimpressionsent="1"><font color="#5c81a7">magicnumber</font></a> 获取文gcd的功能,我们可以使用 <co<wbr>DE><font face="Courier" size="2">Runtime.exec()</font></co<wbr>DE> Ҏ(gu)调用q一命o(h)。但q需要在?file(1) 命o(h)的情况下Q而且q不能识别出所有文件类型。在一般的情况下我们可以简单地Ҏ(gu)扩展名来使用合适的cd理文件。扩展名和类的映关pd?properties 文g中。当需要添加对新的文gcd的支持时Q我们只需d一个新的实?<co<wbr>DE><font face="Courier" size="2">DocumentBuilder</font></co<wbr>DE> 接口的类Qƈ在映文件中d一个映关pd可?/p> <p><a><span><strong><font size="3">    数据库结果集资源</font></strong></span></a></p> <p>        大多数应用用数据库作ؓ(f)怹存储Q对数据库查询结果集索引是一个常见需求?/p> <p>        生成一个数据库l果集资源的实例需要先提供一个查询语句,然后执行查询Q得C个结果集。这个结果集中的内容便是我们需要进行烦(ch)引的对象?co<wbr>DE><font face="Courier" size="2">extractDocuments</font></co<wbr>DE> 的实C是ؓ(f)l果集中的每一行创Z?<co<wbr>DE><font face="Courier" size="2">Document</font></co<wbr>DE> 对象。和文gpȝ资源不同的是Q数据库资源需要放?<co<wbr>DE><font face="Courier" size="2">Document</font></co<wbr>DE> 中的 <co<wbr>DE><font face="Courier" size="2">Field</font></co<wbr>DE> 一般都存在在查询结果集之中。比如一个简单的文章发布站点Q对其后台数据库执行查询 <co<wbr>DE><font face="Courier" size="2">SELECT ID, TITLE, CONTENT FROM ARTICLE</font></co<wbr>DE> q回一个有三列的结果集。对l果集的每一行都?x)被提取Z?<co<wbr>DE><font face="Courier" size="2">Document</font></co<wbr>DE> 对象Q其中包含三?<co<wbr>DE><font face="Courier" size="2">Field</font></co<wbr>DE>Q分别对应这三列?/p> <p>        然而不?<co<wbr>DE><font face="Courier" size="2">Field</font></co<wbr>DE> 的类型是不同的。比?<co<wbr>DE><font face="Courier" size="2">ID</font></co<wbr>DE> 字段一般对?<co<wbr>DE><font face="Courier" size="2">Store.YES</font></co<wbr>DE> ?<co<wbr>DE><font face="Courier" size="2">Index.NO</font></co<wbr>DE> ?<co<wbr>DE><font face="Courier" size="2">Field</font></co<wbr>DE>Q?<co<wbr>DE><font face="Courier" size="2">TITLE</font></co<wbr>DE> 字段则一般对?<co<wbr>DE><font face="Courier" size="2">Store.YES</font></co<wbr>DE> ?<co<wbr>DE><font face="Courier" size="2">Index.TOKENIZED</font></co<wbr>DE> ?<co<wbr>DE><font face="Courier" size="2">Field</font></co<wbr>DE>。ؓ(f)?jin)解册个问题,我们在数据库l果集资源的实现中提供一个类型ؓ(f) <co<wbr>DE><font face="Courier" size="2">Properties</font></co<wbr>DE> ?<co<wbr>DE><font face="Courier" size="2">fieldTypeMappings</font></co<wbr>DE> 属性,用于讄数据库字D|对应?<co<wbr>DE><font face="Courier" size="2">Field</font></co<wbr>DE> 的类型。对于前面的情况来说Q这个属性可能会(x)被配|成cMq样的Ş式:(x)</p> <p> <table style="width: 956px; height: 71px" cellspacing="0" cellpadding="0" width="956" align="center" border="0"> <tbody> <tr> <td> <pre>ID = YES, NO TITLE = YES, TOKENIZED CONTENT = NO, TOKENIZED</pre> </td> </tr> </tbody> </table> <br /> </p> <p>        配合q个映射Q我们便可以生成合适类型的 <co<wbr>DE><font face="Courier" size="2">Field</font></co<wbr>DE>Q完成对l果集烦(ch)引的工作?/p> <p><br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td><img title="使用 Java 开源工具徏立一个灵zȝ搜烦(ch)引擎【{摘?- 大漠落日 - Ҏ(gu)明志 宁静(rn)致远 从容淡定 宠i不惊" height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br /> <img title="使用 Java 开源工具徏立一个灵zȝ搜烦(ch)引擎【{摘?- 大漠落日 - Ҏ(gu)明志 宁静(rn)致远 从容淡定 宠i不惊" height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td> </tr> </tbody> </table> <br /> <br /> </p> <p><a><span><strong><font size="5">    攉索引</font></strong></span></a></p> <p>        完成对资源的索引之后Q还需要让索引为搜索模块所用。前面我们已l说q这里介l的框架主要用于型应用Q考虑到复杂性,我们采取单地分布在各个机器上的索引汇d一个地方的{略?/p> <p>        汇ȝ(ch)引的传输方式可以有很多方案,比如使用 FTP、HTTP、rsync {。甚至烦(ch)引模块和搜烦(ch)模块可以位于同一台机器上Q这U情况下只需要将索引q行本地拯卛_。同前面cMQ我们定义一?<co<wbr>DE><font face="Courier" size="2">Transporter</font></co<wbr>DE> 接口?/p> <p><br />     <a><strong>清单 5. Transporter 接口</strong></a><br /> <table style="width: 956px; height: 71px" cellspacing="0" cellpadding="0" width="956" align="center" border="0"> <tbody> <tr> <td> <pre>public interface Transporter { public void transport(File file); }</pre> </td> </tr> </tbody> </table> <br /> </p> <p>        ?FTP 方式传输ZQ我们?Commons Net 完成传输的操作?/p> <p> <table style="width: 954px; height: 359px" cellspacing="0" cellpadding="0" width="954" align="center" border="0"> <tbody> <tr> <td> <pre>public void transport(File file) throws TransportException { FTPClient client = new FTPClient(); client.connect(host); client.login(username, password); client.changeWorkingDirectory(remotePath); transportRecursive(client, file); client.disconnect(); } public void transportRecursive(FTPClient client, File file) { if (file.isFile() && file.canRead()) { client.storeFile(file.getName(), new FileInputStream(file)); } else if (file.isDirectory()) { client.makeDirectory(file.getName()); client.changeWorkingDirectory(file.getName()); File[] fileList = file.listFiles(); for (File f : fileList) { transportRecursive(client, f); } } } </pre> </td> </tr> </tbody> </table> <br /> </p> <p>        对其他传输方案也有各自的Ҏ(gu)q行处理Q具体用哪?<co<wbr>DE><font face="Courier" size="2">Transporter</font></co<wbr>DE> 的实现被配置?Spring 风格的烦(ch)引模块配|文件中。传输的方式是灵zȝ。比如当需要强调安全性时Q我们可以换用基?SSL ?FTP q行传输。所需要做的只是开发一个?FTP over SSL ?<co<wbr>DE><font face="Courier" size="2">Transporter</font></co<wbr>DE> 实现Qƈ在配|文件中更改 <co<wbr>DE><font face="Courier" size="2">Transporter</font></co<wbr>DE> 的实现即可?/p> <p><br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td><img title="使用 Java 开源工具徏立一个灵zȝ搜烦(ch)引擎【{摘?- 大漠落日 - Ҏ(gu)明志 宁静(rn)致远 从容淡定 宠i不惊" height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br /> <img title="使用 Java 开源工具徏立一个灵zȝ搜烦(ch)引擎【{摘?- 大漠落日 - Ҏ(gu)明志 宁静(rn)致远 从容淡定 宠i不惊" height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td> </tr> </tbody> </table> <br /> <br /> </p> <p><a><span><strong><font size="5">    q行搜烦(ch)</font></strong></span></a></p> <p>        在做?jin)这么多之后Q我们开始接触和用户兌最为紧密的搜烦(ch)模块。注意,我们的框架不包括一个搜索的 Web 前端界面。但是类DL(fng)界面可以在搜索模块的基础上方便地开发出来。基于已l收集好的烦(ch)引进行搜索是个很单的q程。Lucene 已经提供?jin)功能强大?<co<wbr>DE><font face="Courier" size="2">IndexSearcher</font></co<wbr>DE> ?qing)其子类。在q个部分Q我们不?x)再介绍如何使用q些c,而是x(chng)在前文提到过的资源元数据上。元数据从各个资源所在的文g夹中d得到Q它在搜索模块中扮演重要的角艌Ӏ?/p> <p><a><span><strong><font size="3">    构徏一个查?/font></strong></span></a></p> <p>        对不同资源进行搜索的查询Ҏ(gu)q不一栗例如搜索一个论坛里的所有留aӞ我们x(chng)的一般是留言的标题、作者和内容Q而当搜烦(ch)一?FTP 站点Ӟ我们更多x(chng)的是文g名和文g内容。另一斚wQ我们有时可能会(x)使用一个查询去搜烦(ch)多个资源的结果。这正是之前我们在前面所提到的元数据?<a cmimpressionsent="1"><font color="#5c81a7"><co<wbr>DE><font face="Courier" size="2">searchableFields</font></co<wbr>DE> </font></a>?<a cmimpressionsent="1"><font color="#5c81a7"><co<wbr>DE><font face="Courier" size="2">resourceName</font></co<wbr>DE> </font></a>属性的作用。前者指Z个资源中哪些字段是参与搜索的Q后者则用于在搜索时定使用哪个或者哪些烦(ch)引。从技术细节来_(d)只有有了(jin)q些信息Q我们才可以构造出可用?<co<wbr>DE><font face="Courier" size="2">Query</font></co<wbr>DE> 对象?/p> <p><a><span><strong><font size="3">    呈现搜烦(ch)l果</font></strong></span></a></p> <p>        当从 <co<wbr>DE><font face="Courier" size="2">IndexSearcher</font></co<wbr>DE> 对象得到搜烦(ch)l果Q?co<wbr>DE><font face="Courier" size="2">Hits</font></co<wbr>DE>Q之后,当然我们可以直接从中获取需要的|再格式化予以输出。但一来格式化输出搜烦(ch)l果Q尤其在 Web 应用中)(j)是个很常见的需求,可能?x)经常变_(d)二来l果的呈现格式应该是由分散的资源各自定义Q而不是交由搜索模块来定义。基于上面两个原因,我们的框架将使用在资源收集端配置l果输出格式的方式。这个格式由资源元数据中?<a cmimpressionsent="1"><font color="#5c81a7"><co<wbr>DE><font face="Courier" size="2">hitTextPattern</font></co<wbr>DE> </font></a>属性定义。该属性是一个字W串cd的|支持两种语法 </p> <ul> <li>形如 <co<wbr>DE><font face="Courier" size="2">${field_name}</font></co<wbr>DE> 的子字符串都?x)被动态替换成查询l果中各?<co<wbr>DE><font face="Courier" size="2">Document</font></co<wbr>DE> ?<co<wbr>DE><font face="Courier" size="2">Field</font></co<wbr>DE> 的倹{? <li>形如 <co<wbr>DE><font face="Courier" size="2">$function(...) </font></co<wbr>DE>的被解释为函敎ͼ括号内以逗号隔开的符号都被解释成参数Q函数可以嵌套?</li> </ul> <p>        例如搜烦(ch)“具体”q回的搜索结果中包含一?<co<wbr>DE><font face="Courier" size="2">Document</font></co<wbr>DE> 对象Q其 <co<wbr>DE><font face="Courier" size="2">Field</font></co<wbr>DE> 如下表:(x) </p> <p> </p> <p> <table style="width: 955px; height: 86px" cellspacing="0" cellpadding="0" width="955" align="center" border="0"> <tbody> <tr> <th>Field 名称</th> <th>Field 内容</th> </tr> <tr> <td>url</td> <td>http://example.org/article/1.html</td> </tr> <tr> <td>title</td> <td>CZ标题</td> </tr> <tr> <td>content</td> <td>q里是具体的内容?/td> </tr> </tbody> </table> </p> <p>        那么如果 <co<wbr>DE><font face="Courier" size="2">hitTextPatten</font></co<wbr>DE> 被设|ؓ(f)“<co<wbr>DE><font face="Courier" size="2"><a href="${url}">${title}</a><br/>$highlight(${content}, 5, "<b>", "</b>")</font></co<wbr>DE>”Q返回的l果l浏览器解释后可能的昄l果如下Q这只是个演C链接,请不要点击)(j)Q?/p> <p><a cmimpressionsent="1"><font color="#5c81a7">    CZ标题</font></a> <br />     q里?strong>具体</strong>...</p> <p>        上面提到?<co<wbr>DE><font face="Courier" size="2">$highlight()</font></co<wbr>DE> 函数用于在搜索结果中取得最匚w的一D|本,q?sh)显C搜索时使用的短语,其第一个参数是高(sh)昄的文本,W二个参数是昄的文本长度,W三和第四个参数是高?sh)文本时使用的前~和后~?/p> <p>        可以使用正则表达式和文本解析来实现前面所提到的语法。我们也可以使用 <a cmimpressionsent="1"><font color="#5c81a7">JavaCC</font></a> 定义 <co<wbr>DE><font face="Courier" size="2">hitTextPattern</font></co<wbr>DE> 的文法,q而生成词法分析器和语法解析器。这是更为系lƈ且相对而言不易出错的方法。对 JavaCC 的介l不是本文的重点Q?zhn)可以在下面?<a cmimpressionsent="1"><font color="#5c81a7">阅读资源</font></a> 中找到学?fn)资料?/p> <p><br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td><img title="使用 Java 开源工具徏立一个灵zȝ搜烦(ch)引擎【{摘?- 大漠落日 - Ҏ(gu)明志 宁静(rn)致远 从容淡定 宠i不惊" height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br /> <img title="使用 Java 开源工具徏立一个灵zȝ搜烦(ch)引擎【{摘?- 大漠落日 - Ҏ(gu)明志 宁静(rn)致远 从容淡定 宠i不惊" height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td> </tr> </tbody> </table> <br /> <br /> </p> <p><a><span><strong><font size="5">    相关产品</font></strong></span></a></p> <p>        下面列出的是一些与我们所提出的框架所相关或者类似的产品Q?zhn)可以?<a cmimpressionsent="1"><font color="#5c81a7">学习(fn)资料</font></a> 中更多地?jin)解他们?/p> <p><a><span><strong><font size="3">    IBM®OmniFind?Family</font></strong></span></a></p> <p>        OmniFind ?IBM 公司推出的企业搜烦(ch)解决Ҏ(gu)。基?UIMA (Unstructured Information Management Architecture) 技术,它提供了(jin)强大的烦(ch)引和获取信息功能Q支持巨大数量、多U类型的文档资源Q无论是l构化还是非l构化)(j)Qƈ?Lotus®Domino®?WebSphere®Portal 专门q行?jin)优化?/p> <p><a><span><strong><font size="3">    Apache Solr</font></strong></span></a></p> <p>        Solr ?Apache 的一个企业的全文检索项目,实现?jin)一个基?HTTP 的搜索服务器Q支持多U资源和 Web 界面理Q它同样建立?Lucene 之上Qƈ?Lucene 做了(jin)很多扩展Q例如支持动态字D及(qing)唯一键,Ҏ(gu)询结果进行动态分l和qo(h){?/p> <p><a><span><strong><font size="3">    Google SiteSearch</font></strong></span></a></p> <p>        使用 Google 的站Ҏ(gu)索功能可以方便而快捷地建立一个站内搜索引擎。但?Google 的站Ҏ(gu)索基?Google 的网l爬虫,所以无法访问受保护的站点内Ҏ(gu)?Intranet 上的资源。另外,Google 所支持的资源类型也是有限的Q我们无法对其进行扩展?/p> <p><a><span><strong><font size="3">    SearchBlox? </font></strong></span></a></p> <p><a cmimpressionsent="1"><font color="#5c81a7">        SearchBlox</font></a> 是一个商业的搜烦(ch)引擎构徏框架。它本n是一?J2EE lgQ和我们的框架类|也支持对|页和文件系l等资源q行索引Q进而进行搜索?/p> <p><br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td><img title="使用 Java 开源工具徏立一个灵zȝ搜烦(ch)引擎【{摘?- 大漠落日 - Ҏ(gu)明志 宁静(rn)致远 从容淡定 宠i不惊" height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br /> <img title="使用 Java 开源工具徏立一个灵zȝ搜烦(ch)引擎【{摘?- 大漠落日 - Ҏ(gu)明志 宁静(rn)致远 从容淡定 宠i不惊" height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td> </tr> </tbody> </table> <br /> <br /> </p> <p><a><span><strong><font size="5">    q需考虑的问?/font></strong></span></a></p> <p>        本文介绍的思想试图利用开源的工具解决中小型应用中的常见问题。当?dng)作?f)一个框Ӟ它还有很多不I下面列DZ些可以进行改q的地方?/p> <p><a><span><strong><font size="3">    性能考虑</font></strong></span></a></p> <p>        当需要进行烦(ch)引的资源数目不多Ӟ隔一定的旉q行一ơ完全烦(ch)引不?x)占用很长时间。用一?2G 内存QXeon 2.66G 处理器的服务器进行实际测试,发现Ҏ(gu)据库资源的烦(ch)引占用的旉很少Q一千多条记录花费的旉?1 U到 2 U之内。而对 1400 多个文gq行索引耗时大约十几U。但在大型应用中Q资源的定w是巨大的Q如果每ơ都q行完整的烦(ch)引,耗费的时间会(x)很惊人。我们可以通过跌已经索引的资源内容,删除已不存在的资源内容的索引Qƈq行增量索引来解册个问题。这可能?x)涉及(qing)文件校验和索引删除{?/p> <p>        另一斚wQ框架可以提供查询缓存来提高查询效率。框架可以在内存?sh)徏立一U缓存,q用如 <a cmimpressionsent="1"><font color="#5c81a7">OSCache</font></a> ?<a cmimpressionsent="1"><font color="#5c81a7">EHCache</font></a> 实现盘?sh)的二~存。当索引的内容变化不频繁Ӟ使用查询~存更会(x)明显地提高查询速度、降低资源消耗?/p> <p><a><span><strong><font size="3">    分布式烦(ch)?/font></strong></span></a></p> <p>        我们的框架可以将索引分布在多台机器上。搜索资源时Q查询被 flood 到各个机器上从而获得搜索结果。这样可以免M输烦(ch)引到某一C央服务器的过E。当然也可以Z实现?jin)分布式哈希?QDHTQ的l构?P2P |络Q配合烦(ch)引复?(Replication)Q得应用程序更为安全,可靠Q有伸羃性。在 <a cmimpressionsent="1"><font color="#5c81a7">阅读资料</font></a> 中给Z(jin) 一关于构建分布式环境下全文搜索的可行性的论文?</p> <p><a><span><strong><font size="3">    安全?/font></strong></span></a></p> <p>        目前我们的框架ƈ没有涉及(qing)到安全性。除?jin)依赖资源本w的讉K控制Q如受保护的|页和文件系l等Q之外,我们q可以从两方面增强框架本w的安全性:(x) </p> <ol> <li>考虑C个组l的搜烦(ch)功能对不同用L(fng)权限讄不一定一P可以支持对用戯色的定义Q实行对搜烦(ch)模块的访问控制? <li>在资源烦(ch)引模块中实现一U机Ӟ让资源可以限制自己暴露的内容Q从而羃?yu)?ch)引模块的索引范围。这可以cL robots 文g可以规定搜烦(ch)引擎爬虫的行为?</li> </ol> <p> </p> <p><br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td><img title="使用 Java 开源工具徏立一个灵zȝ搜烦(ch)引擎【{摘?- 大漠落日 - Ҏ(gu)明志 宁静(rn)致远 从容淡定 宠i不惊" height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br /> <img title="使用 Java 开源工具徏立一个灵zȝ搜烦(ch)引擎【{摘?- 大漠落日 - Ҏ(gu)明志 宁静(rn)致远 从容淡定 宠i不惊" height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td> </tr> </tbody> </table> <br /> <br /> </p> <p><a><span><strong><font size="5">    ȝ</font></strong></span></a></p> <p>        通过上文的介l,我们认识?jin)一个可扩展的框Ӟq(ch)引模块和搜烦(ch)模块两部分组成。它可以灉|地适应不同的应用场景。如果需要更独特的需求,框架本n预留?jin)可以扩展的接口Q我们可以通过实现q些接口完成功能的定制。更重要的是q一切都是徏立在开源Y件的基础之上。希望本文能为?zhn)揭示开源的力量Q体验用开源工L(fng)装?zhn)自己的解x(chng)案所带来的莫大快乐?/p> <img src ="http://www.tkk7.com/zphab/aggbug/295622.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/zphab/" target="_blank">张^?/a> 2009-09-18 23:39 <a href="http://www.tkk7.com/zphab/articles/295622.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>让GC扫面持久区permanent generation【{摘?/title><link>http://www.tkk7.com/zphab/articles/295619.html</link><dc:creator>张^?/dc:creator><author>张^?/author><pubDate>Fri, 18 Sep 2009 15:24:00 GMT</pubDate><guid>http://www.tkk7.com/zphab/articles/295619.html</guid><wfw:comment>http://www.tkk7.com/zphab/comments/295619.html</wfw:comment><comments>http://www.tkk7.com/zphab/articles/295619.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/zphab/comments/commentRss/295619.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/zphab/services/trackbacks/295619.html</trackback:ping><description><![CDATA[        一般GC法也是?x)照permanent generation的,每次permanent generation满了(jin)要做扩展前都?x)触发一ơFULL GCQ除非设|了(jin)-Xnoclassgc?nbsp;<br /> <br />         另外如果使用CMSQConcMarkSweep GCQ算法的话,开?XX:+UseConcMarkSweepGC标志Q默认情况下是不会(x)扫描permanent generation的,需要同时打开下面两个标志位才能让CMS GC扫描permanent generation?nbsp;<br />         -XX:+CMSPermGenSweepingEnabled <br />         -XX:+CMSClassUnloadingEnabled <br /> <br />         PSQ只针对SUN的JVM有效? <img src ="http://www.tkk7.com/zphab/aggbug/295619.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/zphab/" target="_blank">张^?/a> 2009-09-18 23:24 <a href="http://www.tkk7.com/zphab/articles/295619.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <p>лǵվܻԴȤ</p> <a href="http://www.tkk7.com/" title="亚洲av成人片在线观看">亚洲av成人片在线观看</a> <div class="friend-links"> </div> </div> </footer> վ֩ģ壺 <a href="http://bearsou.com" target="_blank">һػ¼Ѳŷ</a>| <a href="http://t66ycom.com" target="_blank">ѸӰ߹ۿ</a>| <a href="http://155562.com" target="_blank">91߾Ʒ</a>| <a href="http://51caox.com" target="_blank">Ƶһվ</a>| <a href="http://jinlaifubuxiugang.com" target="_blank">þþþþþ99Ʒ </a>| <a href="http://cct68.com" target="_blank">Ʒһ߹ۿ</a>| <a href="http://jjv5.com" target="_blank">ֻˬһëƬѹۿ</a>| <a href="http://wwwy66y6.com" target="_blank">Ļ</a>| <a href="http://51jingpai.com" target="_blank">aëƬ100ѹۿ</a>| <a href="http://fenglengqi.com" target="_blank">avƬ߹ۿ16Ů </a>| <a href="http://my94ok.com" target="_blank">ŷպһ</a>| <a href="http://31xyz.com" target="_blank">߹ۿѴվ</a>| <a href="http://815389.com" target="_blank">vavava</a>| <a href="http://chuguo65.com" target="_blank">ůůձ</a>| <a href="http://hn283.com" target="_blank">޾ƷƵѿ</a>| <a href="http://wwkk3.com" target="_blank">˳վ߿</a>| <a href="http://www6yg6yg.com" target="_blank">AVպAVһ</a>| <a href="http://zzz134.com" target="_blank">AëƬA</a>| <a href="http://bii59.com" target="_blank">ִˬƵ </a>| <a href="http://ivr69.com" target="_blank">޹ƷۺϾþ20</a>| <a href="http://js06vip.com" target="_blank">ˬƵ</a>| <a href="http://linmh.com" target="_blank">ɫҳѹۿ</a>| <a href="http://www65axax.com" target="_blank">Ӱ޴ɫ</a>| <a href="http://www045888.com" target="_blank">պƷרѲ</a>| <a href="http://gachi1151.com" target="_blank">Թ</a>| <a href="http://020iws.com" target="_blank">ۺϽ޺ݺ</a>| <a href="http://fennenll.com" target="_blank">ĻѸƵ</a>| <a href="http://aiqingdao999.com" target="_blank">ŷ޹Ʒ㶮</a>| <a href="http://xianliwang.com" target="_blank">ѿ20</a>| <a href="http://140699.com" target="_blank">һһһëƬëƬ</a>| <a href="http://wivyswap.com" target="_blank">ۺij</a>| <a href="http://hsewx.com" target="_blank">þùƷ</a>| <a href="http://yw5168.com" target="_blank">þþþ޾Ʒ</a>| <a href="http://www003924.com" target="_blank">Ůڵվ</a>| <a href="http://jte-sh.com" target="_blank">þþwww˳</a>| <a href="http://woaisouluo.com" target="_blank">޵һƷӰ</a>| <a href="http://miyatb.com" target="_blank">AV߹ۿɫ </a>| <a href="http://sxjttxkywl.com" target="_blank">Ʒާѡ2021</a>| <a href="http://sdzsx.com" target="_blank">þþþAVרɫ</a>| <a href="http://jdvgo.com" target="_blank">91Ѳˬ˿</a>| <a href="http://33303339.com" target="_blank">Ƭѹۿþ</a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>