📄 searchservlet.java
字号:
protected void showHTMLBody() throws IOException, ServletException { // Show HTML body. DEBUG(resp,"showHTMLBody"); showBodyHeader(); out.print("<div class=home>"); showQueryFormAbove(); if (query != null) { processQuery(); showQuickLinks(); showSpellingSuggestion(); showResultsTop(); showSubtopicsAbove(); } else { showTopicsBrowsePage(); } // Flush the data to the client, so it can start showing the page. // We want to start getting the response to the client as soon as possible. // Note: This will close keep-alive connections as we can't send Content-Length // Also, don't flush() prior to Spelling suggestion, as we might // want to restart the request with a re-spelling of terms. out.flush(); if (query != null) { showRelatedTopicsAbove(); if (haveSearchResults()) { if (isSearchResultAvailable(st-1)) showSearchResults(); else showNoMoreResults(); } else showNoHits(); showSubtopicsBelow(); showRelatedTopicsBelow(); showFootnotes(); } showQueryFormBelow(); out.print("</div>"); // class=home showBodyFooter(); DEBUG(resp,"/showHTMLBody"); } /** * Translate a message into the current UI language. * @return the translated message. * @param msg the English message to translate. * If a translation of the message is not available, the original message is returned. */ protected String Translate(String msg) { // REMIND: Diagnostic logging if translation not available. return text(textMap,msg); } /** * Translate a message with a single insertion point. * @return the translated message, with text inserted. * @param msg the English message to translate. * @param marker the text to replace (eg: "%s" or "%d") * @param insert the text to insert */ protected String Translate(String msg, String marker, String insert) { String tx = Translate(msg); int where = tx.indexOf(marker); if (where != -1) { return (tx.substring(0,where) + insert + tx.substring(where+marker.length())); } return tx; } /** * Determine if there are results to show. * @return <code>true</code> if there are search results available. * @see #isSearchResultAvailable */ protected boolean haveSearchResults() { return (searchResults != null && !searchResults.isEmpty()); } /** * Show the topics, and all their sub-topics. * Note: The Ultraseek standard interface limits to a total * of 50 topics being shown. This version shows * all topics without limit. * @param subTopics the topics to show * @param indent how many spaces each topic line should be indented. * @see #showAllTopicsBrowsePage */ protected void showAllTopics(Collection subTopics, int indent) { if (subTopics==null || subTopics.size() < 1) return; // Sort topics by name TopicComparator byTopicName = new TopicComparator(); SortedSet topicsList = new TreeSet(byTopicName); topicsList.addAll(subTopics); Iterator it = topicsList.iterator(); while (it.hasNext()) { Object o = it.next(); if (o instanceof StandardSearchTopic) { StandardSearchTopic sub = (StandardSearchTopic) o; out.print("<br>"); for (int i = 0; i < indent; i++) out.print(" "); showTopicName(sub,true,null); showAllTopics( sub.getSubTopics(), indent + 2 ); } } } /** * Show the "expand all topics" browse page. * @see #showAllTopics * @see #showTopLevelTopicsBrowsePage */ protected void showAllTopicsBrowsePage() { if (getStyleSettingBoolean("show_all_topics")) { String href = makeURLNavigation("tt", 0); if (!isEmpty(href)) { out.print( "<a href=\"" ); out.print( HTMLEncoded(href) ); out.print( "\"><i>" ); out.print( HTMLEncoded(Translate("Show only top level topics"))); out.print( "</i></a><br><br>" ); } } out.print("<p><b class=label>" ); out.print( HTMLEncoded(Translate("Topics"))); out.print( ":</b>" ); showAllTopics(topic.getSubTopics(),0); out.print( "<br>" ); } /** * Show the "top level topics" browse page. * @see #showAllTopicsBrowsePage */ protected void showTopLevelTopicsBrowsePage() { if (getStyleSettingBoolean("show_all_topics")) { String href = makeURLNavigation("tt", 1); if (!isEmpty(href)) { out.print( "<a href=\"" ); out.print( HTMLEncoded(href) ); out.print( "\"><i>" ); out.print( HTMLEncoded(Translate("Expand all topics"))); out.print( "</i></a><br><br>" ); } } String label = Translate("Topics"); Collection subTopics = topic.getSubTopics(); showTopics(subTopics, label, getStyleSettingInt("topics_columns",3), getStyleSettingInt("topics_childcount",3), getStyleSettingInt("topics_child_indent",1), 0 // (false) show topic paths ); out.print( "<br>" ); } protected void showTopicsBrowsePage() throws ServletException { DEBUG(out,"showTopicsBrowsePage"); if (getPageDisplayMode() == MODE_INDEX_PAGE && topic != null) { Collection subTopics = topic.getSubTopics(); if (subTopics!=null && subTopics.size()>0) { out.print("<p>"); out.println("<div class=topics>"); if (tt==1) showAllTopicsBrowsePage(); else showTopLevelTopicsBrowsePage(); out.println("</div>"); } } DEBUG(out,"/showTopicsBrowsePage"); } protected void showSubtopicsAbove() { if (getStyleSettingBoolean("subtopics_above")) showSubtopicsBrowsePage(); } protected void showSubtopicsBelow() { if (getStyleSettingBoolean("subtopics_below")) showSubtopicsBrowsePage(); } protected void showSubtopicsBrowsePage() { DEBUG(out,"showSubtopicsBrowsePage"); // Show subtopics, if this is a topics browse page. if (isEmpty(qtxt) && isEmpty(fs) && topic!=null && st==1) { Collection subTopics = topic.getSubTopics(); if (subTopics!=null && subTopics.size()>0) { out.println("<p>"); out.println("<div class=topics>"); String label; if (topic.getID().equals(ht)) label = Translate("Topics"); else label = Translate("Subtopics"); showTopics(subTopics, label, getStyleSettingInt("subtopics_columns",3), getStyleSettingInt("subtopics_childcount",3), getStyleSettingInt("subtopics_child_indent",1), 0 // (false) show topic paths ); out.println("</div>"); } } DEBUG(out,"/showSubtopicsBrowsePage"); } /** * Estimates the number of search results. * <p> * Sets the estimate of search hits <em>found on the server</em> * into <code>serverHitCount</count> and sets the estimate of * <em>hits available to display</em> into <code>availableHitCount</em>. * <p> * These values can be different for several reasons. * For instance, <code>DateSortingSearchable</code> will * sort the top 100 relevant search hits, so the maximum value for * <code>availableHitCount</code> is 100. * <p> * The values can change as search results are processed, * due to the impact of background processing threads * and result filtering. * <p> * If you need <em>exact</em> counts, you must read the * SearchResultList until all results have been read. * <code>SearchResultList.size</code> will then give the * accurate number for <code>availableHitCount</code>, * but <code>serverHitCount</code> is still an <em>estimate</em> * from the search server. * <p> * Your application will have <em>much</em> better performance if you * do not generate a completely accurate count. */ protected void setHitCounts(SearchResultList srl) throws IOException { serverHitCount = srl.getResultCount(); availableHitCount = srl.size(); } protected void processQuery() throws IOException, ServletException { if (query==null || searchable==null) return; DEBUG(out,"processQuery"); serverHitCount = 0; availableHitCount = 0; int numErrorRetries = 0; boolean retrying = false; do { try { if (retrying) DEBUG(out,"processQuery - retrying"); retrying = false; searchResults = makeResults(searchable,query); setHitCounts(searchResults); relatedTopics = makeRelatedTopics(topic,searchResults); } catch (IOException e) { DEBUG(out,"processQuery " + e); if (!(server instanceof MirrorGroup)) throw e; if (numErrorRetries++ > 0) throw e; retrying = true; } catch (RuntimeException e) { DEBUG(out,"processQuery " + e); if (!(server instanceof MirrorGroup)) throw e; if (numErrorRetries++ > 0) throw e; retrying = true; } catch (QueryNotSupportedException e) { DEBUG(out,"processQuery " + e); throw new ServletException(e.getLocalizedMessage(),e); } } while (retrying); DEBUG(out,"/processQuery"); } protected void showQuickLinksSearchResult(QuickLinksSearchResult ql) throws IOException { String url = ql.getURLString(); out.print("<p><font class=qltext><a href=\""); out.print(HTMLEncoded(url)); out.print("\">"); String title = ql.getTitle(); if (isEmpty(title)) title = url; out.print(HTMLEncoded(title)); out.print("</a><br>"); if (ql.hasHTMLDescription()) { out.print(ql.getDescription()); } else { printDescription(out,ql.getDescription()); } out.print("</font></p>"); } protected void showQuickLinks() throws IOException, ServletException { if (quickLinks == null) return; if (isEmpty(qtxt)) return; DEBUG(out,"showQuickLinks"); SearchResultList qklinks; try { qklinks = quickLinks.search(query); } catch (QueryNotSupportedException e) { return; } Iterator it = qklinks.iterator(); boolean first = true; try { while (it.hasNext()) { QuickLinksSearchResult ql = (QuickLinksSearchResult) it.next(); if (first) { first = false; showedQuickLink = true; out.println("<div class=quicklinks>"); out.println("<table width=\""+pw+"\""+BORDER+"><tr><td>" ); out.print("<table width=\"95%\"; class=qltable"+BORDER+"><tr><td>"); out.print("<b><font class=qlheader>"); out.print(HTMLNonBreaking(Translate("Quick Links"))); out.print(":</font></b><br>"); } showQuickLinksSearchResult(ql); } } catch (NoSuchElementException e) { // Normal end of list - not an error } catch (XPARuntimeException e) { // ignore IOException during hasNext() or next() log( "showQuickLinks problem", e ); } catch (IOException e) { // ignore IOException during quick links processing log( "showQuickLinks problem", e ); } if (!first) { out.print("</td><td width=\"5%\"> </td></tr></table>"); out.println("\n<hr size=1 width=\""+pw+"\" align=left>"); out.println("</td></tr></table></div>"); } DEBUG(out,"/showQuickLinks"); } protected void showSpellingSuggestion() throws IOException, ServletException { if (!getStyleSettingBoolean("enable_spell",true)) return; DEBUG(out,"showSpellingSuggestion"); if (isEmpty(oldqt) && !isEmpty(qtxt))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -