捕风之巢

统计

留言簿(3)

java友情链接

阅读排行榜

评论排行榜

j2ee小应用

附加功能 (目录)
实现图片上传 (目录)
  用户必须能够上传图片,因此需要文件上传的功能。比较常见的文件上传组件有Commons FileUpload(http://jakarta.apache.org/commons/fileupload/a>)和COS FileUpload(http://www.servlets.com/cos),Spring已经完全集成了这两种组件,这里我们选择Commons FileUpload。
  由于Post一个包含文件上传的Form会以multipart/form-data请求发送给服务器,必须明确告诉 DispatcherServlet如何处理MultipartRequest。首先在dispatcher-servlet.xml中声明一个 MultipartResolver:

<bean id="multipartResolver"
       class
="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        
<!-- 设置上传文件的最大尺寸为1MB -->
        
<property name="maxUploadSize">
        
<value>1048576</value>
    
</property>
</bean>


  这样一旦某个Request是一个MultipartRequest,它就会首先被MultipartResolver处理,然后再转发相应的Controller。
  在UploadImageController中,将HttpServletRequest转型为MultipartHttpServletRequest,就能非常方便地得到文件名和文件内容:

public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
    
// 转型为MultipartHttpRequest:
    MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
    
// 获得文件:
    MultipartFile file = multipartRequest.getFile("file");
    
// 获得文件名:
    String filename = file.getOriginalFilename();
    
// 获得输入流:
    InputStream input = file.getInputStream();
    
// 写入文件
}


生成缩略图 (目录)
  当用户上传了图片后,必须生成缩略图以便用户能快速浏览。我们不需借助第三方软件,JDK标准库就包含了图像处理的API。我们把一张图片按比例缩放到120X120大小,以下是关键代码:

public static void createPreviewImage(String srcFile, String destFile) {
    
try {
        File fi 
= new File(srcFile); // src
        File fo = new File(destFile); // dest
        BufferedImage bis = ImageIO.read(fi);

        
int w = bis.getWidth();
        
int h = bis.getHeight();
        
double scale = (double)w/h;
        
int nw = IMAGE_SIZE; // final int IMAGE_SIZE = 120;
        int nh = (nw * h) / w;
        
if( nh>IMAGE_SIZE ) {
            nh 
= IMAGE_SIZE;
            nw 
= (nh * w) / h;
        }

        
double sx = (double)nw / w;
        
double sy = (double)nh / h;

        transform.setToScale(sx,sy);
        AffineTransformOp ato 
= new AffineTransformOp(transform, null);
        BufferedImage bid 
= new BufferedImage(nw, nh, BufferedImage.TYPE_3BYTE_BGR);
        ato.filter(bis,bid);
        ImageIO.write(bid, 
"jpeg", fo);
    }
 catch(Exception e) {
        e.printStackTrace();
        
throw new RuntimeException("Failed in create preview image. Error: " + e.getMessage());
    }

}

实现RSS (目录)
  RSS是一个标准的XML文件,Rss阅读器可以读取这个XML文件获得文章的信息,使用户可以通过Rss阅读器而非浏览器阅读Blog,我们只要动态生成这个XML文件便可以了。RSSLibJ是一个专门读取和生成RSS的小巧实用的Java库,大小仅25k,可以从http://sourceforge.net/projects/rsslibj/下载rsslibj-1_0RC2.jar和它需要的EXMLjar两个文件,然后复制到web/WEB-INF/lib/下。
  使用RSSLibJ异常简单,我们先设置好HttpServletResponse的Header,然后通过RSSLibJ输出XML即可:

Channel channel = new Channel();
channel.setDescription(account.getDescription());
baseUrl 
= baseUrl.substring(0, n);
channel.setLink(
"http://server-name/home.c?accountId=" + accountId);
channel.setTitle(account.getTitle());
List articles 
= facade.getArticles(accountId, account.getMaxPerPage(), 1);
Iterator it 
= articles.iterator();
while(it.hasNext()) {
    Article article 
= (Article)it.next();
    channel.addItem(
"http://server-name/article.c?articleId=" + article.getArticleId(),
        article.getSummary(), article.getTitle()
    );
}

// 输出xml:
response.setContentType("text/xml");
PrintWriter pw 
= response.getWriter();
pw.print(channel.getFeed(
"rss"));
pw.close();

实现全文搜索 (目录)
  全文搜索能大大方便用户快速找到他们希望的文章,为blog增加一个全文搜索功能是非常必要的。然而,全文搜索不等于SQL的LIKE语句,因为关系数据库的设计并不是为全文搜索设计的,数据库索引对全文搜索无效,在一个几百万条记录中检索LIKE '%A%'可能会耗时几分钟,这是不可接受的。幸运的是,我们能使用免费并且开源的纯Java实现的Lucene全文搜索引擎,Lucene可以非常容易地集成到我们的blog中。
  Lucene不提供直接对文件,数据库的索引,只提供一个高性能的引擎,但接口却出人意料地简单。我们只需要关心以下几个简单的接口:
  Document:代表Lucene数据库的一条记录,也代表搜索的一条结果。
  Field:一个Document包含一个或多个Field,类似关系数据库的字段。
  IndexWriter:用于创建新的索引,也就是向数据库添加新的可搜索的大段字符串。
  Analyzer:将字符串拆分成单词(Token),不同的文本对应不同的Analyzer,如HtmlAnalyzer,PDFAnalyzer。
  Query:封装一个查询,用于解析用户输入。例如,将“bea blog”解析为“同时包含bea和blog的文章”。
  Searcher:搜索一个Query,结果将以Hits返回。
  Hits:封装一个搜索结果,包含Document集合,能非常容易地输出结果。
  下一步,我们需要为Article表的content字段建立全文索引。首先为Lucene新建一个数据库,请注意这个数据库是Lucene专用的,我们不能也不必知道它的内部结构。Lucene的每个数据库对应一个目录,只需要指定目录即可:

String indexDir = "C:/search/blog";
IndexWriter indexWriter 
= new IndexWriter(indexDir, new StandardAnalyzer(), true);
indexWriter.close();

  然后添加文章,让Lucene对其索引:

String title 
= "文章标题" // 从数据库读取
String content = "文章内容" // 从数据库读取
// 打开索引:
IndexWriter indexWriter = new IndexWriter(indexDir, new StandardAnalyzer(), false);
// 添加一个新记录:
Document doc = new Document();
doc.add(Field.Keyword(
"title", title));
doc.add(Field.Text(
"content", content));
// 建立索引:
indexWriter.addDocument(doc);
// 关闭:
indexWriter.close();

 要搜索文章非常简单:
 然后添加文章,让对其索引:

String title = "文章标题" // 从数据库读取
String content = "文章内容" // 从数据库读取
// 打开索引:
IndexWriter indexWriter = new IndexWriter(indexDir, new StandardAnalyzer(), false);
// 添加一个新记录:
Document doc = new Document();
doc.add(Field.Keyword(
"title", title));
doc.add(Field.Text(
"content", content));
// 建立索引:
indexWriter.addDocument(doc);
// 关闭:
indexWriter.close();

  要搜索文章非常简单:

Searcher searcher = new IndexSearcher(dir);
Query query 
= QueryParser.parse(keyword, "content"new StandardAnalyzer());
Hits hits 
= searcher.search(query);
if(hits != null){
    
for(int i = 0;i < hits.length(); i++){
        Document doc 
= hits.doc(i);
        System.out.println(
"found in " + doc.get("title"));
        System.out.println(doc.get(
"content"));
    }

}

searcher.close();
  我们设计一个LuceneSearcher类封装全文搜索功能,由于必须锁定数据库所在目录,我们把数据库设定在/WEB-INF/search/下,确保用户不能访问,并且在配置文件中初始化目录:

<bean id="luceneSearcher" class="org.crystalblog.search.LuceneSearcher">
    
<property name="directory">
       
<value>/WEB-INF/search/</value>
    
</property>
</bean>

效果如下:


(图4:search)

发送Email (目录)
  Blog用户可以让系统将来访用户的留言发送到注册的Email地址,为了避免使用SMTP发信服务器,我们自己手动编写一个SendMail组件,直接通过SMTP协议将Email发送到用户信箱。
  SendMail组件只需配置好DNS服务器的IP地址,即可向指定的Email信箱发送邮件。并且,SendMail使用缓冲队列和多线程在后台发送Email,不会中断正常的Web服务。具体代码请看SendMail.java。

测试 (目录)
  服务器配置为:P4 1.4G,512M DDR,100M Ethernet,Windows XP Professional SP2。
  测试服务器分别为WebLogic Server 8.1,Tomcat 4.1/5.0,Resin 2.1.1。
  测试数据库为MS SQL Server 2000 SP3。如果你使用Oracle或者DB2,MySQL等其他数据库并测试成功,请将SQL初始化脚本和详细配置过程发一份给我,谢谢。
  由于时间有限,没有作进一步的调优。WebLogic Server和iBatis有很多优化选项,详细配置可以参考相关文档。

中文支持 (目录)
  测试发现,中文不能在页面中正常显示,为了支持中文,首先在web.xml加入Filter,用于将输入编码设置为gb2312:
<filter>
    
<filter-name>encodingFilter</filter-name>
    
<filter-class>org.crystalblog.web.filter.EncodingFilter</filter-class>
    
<init-param>
        
<param-name>encoding</param-name>
        
<param-value>gb2312</param-value>
    
</init-param>
</filter>
<filter-mapping>
    
<filter-name>encodingFilter</filter-name>
    
<url-pattern>/*</url-pattern>
</filter-mapping>

  然后用文本工具搜索所有的.htm,.html,.properties文件,将“iso-8859-1”替换为“gb2312”,现在页面中文已经能正常显示,但是Lucene仍不能正常解析中文,原因是标准的StandardA?nalyzer只能解析英文,可以从网上下载一个支持中文的 Analyzer。

posted on 2006-10-13 10:08 捕风 阅读(247) 评论(1)  编辑  收藏 所属分类: java高级

评论

# re: j2ee小应用 2008-01-19 08:41 touchsky88

Dealing with Chinese, unicode I suppose is a pain on the neck.

Add the following part solve the unicode problem.
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设置上传文件的最大尺寸为1MB -->
<property name="maxUploadSize">
<value>1048576</value>
</property>
<property name="defaultEncoding">
<value>UTF-8</value>
</property>
</bean>  回复  更多评论   


只有注册用户登录后才能发表评论。


网站导航: