摘要:市長(zhǎng)信箱郵件查詢服務(wù)使用構(gòu)建工程一直想用做個(gè)微服務(wù)練練手為后續(xù)部署到打下基礎(chǔ)今天比較空閑就開(kāi)始把部分想法落地了概覽用來(lái)練手的應(yīng)用是一個(gè)市長(zhǎng)信箱的內(nèi)容抓取與檢索頁(yè)面鑒于我的八卦特質(zhì)總想了解下周邊的一些投訴信息而成都的市長(zhǎng)信箱是一個(gè)絕好的信息來(lái)
市長(zhǎng)信箱郵件查詢服務(wù): 使用SpringBoot構(gòu)建工程
一直想用SpringBoot做個(gè)微服務(wù),練練手, 為后續(xù)部署到docker打下基礎(chǔ). 今天比較空閑, 就開(kāi)始把部分想法落地了.
https://github.com/ybak/mycrawler
用來(lái)練手的demo應(yīng)用是一個(gè)市長(zhǎng)信箱的內(nèi)容抓取與檢索頁(yè)面. 鑒于我的八卦特質(zhì),總想了解下周邊的一些投訴信息. 而成都的市長(zhǎng)信箱是一個(gè)絕好的信息來(lái)源.
信件格式:來(lái)信情況 | 張三 |
---|---|
來(lái)信標(biāo)題 | 生活困擾 |
來(lái)信內(nèi)容 | 尊敬市長(zhǎng)你好我們有十三戶污水到我處無(wú)法排走... |
辦理結(jié)果 | 郫縣(2016-05-20 11:31:10): 來(lái)信人: 您好! ... |
這個(gè)demo應(yīng)用的主要功能有:
從市長(zhǎng)信箱抓取所有的市民投訴并保存
提供按關(guān)鍵字檢索的web頁(yè)面來(lái)檢索感興趣的投訴信息
按照循序漸進(jìn)的原則, 先實(shí)現(xiàn)只實(shí)現(xiàn)基本功能, 不考慮性能, 后續(xù)再進(jìn)行優(yōu)化.
Mysql的提供了基本的模糊匹配功能, 且SpringBoot中,能方便的集成JPA.
使用Mysql保存抓取信息, 并提供給Web應(yīng)用查詢, 是很容易實(shí)現(xiàn)的. 所以該demo應(yīng)用的第一版技術(shù)設(shè)計(jì)如下:
SpringBoot的代碼使用maven的多模塊組織:
父模塊(聲明此工程的spring-boot的版本)
pom.xml
org.springframework.boot spring-boot-starter-parent 1.3.5.RELEASE
crawler-downloader:抓取模塊
: pom.xml
crawler-persistence:存儲(chǔ)模塊(使用spring的jpa實(shí)現(xiàn)orm)
: pom.xml
org.springframework.boot spring-boot-starter-data-jpa
crawler-search-web:頁(yè)面模塊(使用spring的thymeleaf實(shí)現(xiàn)mvc和rest api)
: pom.xml
org.springframework.boot spring-boot-starter-thymeleaf
接下來(lái),分別介紹各個(gè)模塊的細(xì)節(jié):
crawler-persistence:存儲(chǔ)模塊根據(jù)信件內(nèi)容的格式,設(shè)計(jì)存儲(chǔ)信件的表結(jié)構(gòu)如下:
這里我使用的rxjava-jdbc來(lái)進(jìn)行數(shù)據(jù)的插入.相比JPA, rxjava-jdbc如果做基礎(chǔ)的查詢和插入操作使用起來(lái)很方便.
// 查詢郵件詳情url IterableWEB展示的DB操作> results = db .select("select id, url from chengdu12345 limit ?,?").parameters(i * 50, 50) .getAs(Integer.class, String.class).toBlocking().toIterable(); //插入郵件記錄 int updates = db.update("insert into chengdu12345(url, title, sender, accept_unit, status, category, views, create_date) values (?,?,?,?,?,?,?,?)") .parameters(url, title, sender, receiveUnit, status, category, views, publishDate) .execute();
查詢數(shù)據(jù)庫(kù)的郵件信息時(shí), 會(huì)涉及到分頁(yè), 模糊匹配, 這個(gè)時(shí)候rxjava-jdbc顯的有些力不從心了. 而spring-data的大量的模板方法,會(huì)讓查詢代碼簡(jiǎn)化. 所以這里我使用了spring-data-jpa的方式來(lái)進(jìn)行查詢.
@Table(name = "chengdu12345") @NamedQuery(name = "Mail.search", query = "select m from Mail m where m.title like ?1 or m.content like ?1 or m.result like ?1") public class Mail implements Serializable {...} ...... public interface MailRepository extends Repository{ Page search(String keyword, Pageable pageable); } ...... public class MailService { @Autowired private MailRepository mailRepository; public Page search(String keyword, Pageable pageable) { return mailRepository.search("%" + keyword + "%", pageable); } }
MailService 的search方法,只需傳入Pageable 實(shí)例, spring-data將自動(dòng)為我們處理好分頁(yè)的邏輯, 非常方便.
crawler-downloader:抓取模塊市長(zhǎng)信箱的郵件展示列表中只有郵件標(biāo)題和郵件詳情鏈接等基礎(chǔ)信息,沒(méi)有郵件正文和處理結(jié)果詳情. 我的抓取流程是:
遍歷所有的郵件列表的分頁(yè)信息, 將郵件基礎(chǔ)信息保存到數(shù)據(jù)庫(kù).
遍歷數(shù)據(jù)庫(kù)中的所有已保存的郵件基礎(chǔ)信息, 取出郵件詳情鏈接, 再對(duì)該鏈接進(jìn)行抓取, 取得內(nèi)容進(jìn)行分析并保存到數(shù)據(jù)庫(kù)中.
我用來(lái)抓取頁(yè)面的http客戶端類庫(kù)是okhttp,
okhttp不但提供了簡(jiǎn)潔的api, 還在內(nèi)部建立了url連接池, 在快速抓取頁(yè)面時(shí), 減少了tcp鏈接的建立, 提高了速度, 也降低了抓取失敗的幾率.
public class HtmlUtil { static OkHttpClient client = new OkHttpClient(); public static String getURLBody(String url) throws IOException { Request request = new Request.Builder() .url(url) .build(); Response response = client.newCall(request).execute(); if (!response.isSuccessful()) { response.body().close(); throw new IllegalArgumentException(response.message()); } return response.body().string(); } }
頁(yè)面解析的列庫(kù)我使用了Jsoup, Jsoup也可以直接用來(lái)抓取頁(yè)面. 但它沒(méi)有提供易用的連接池機(jī)制. 默認(rèn)每次抓取都會(huì)創(chuàng)建tcp連接. 在快速抓取頁(yè)面的情況下很容易打開(kāi)過(guò)多的端口,從而造成抓取失敗. 但Jsoup的html解析api卻是相當(dāng)?shù)膹?qiáng)大. 尤其它的對(duì)css selector的支持, 選取dom就像使用jquery一樣方便.
String html = HtmlUtil.getURLBody(pageUrl); Document doc = Jsoup.parse(html); Elements elements = doc.select("div.left5 ul li.f12px"); for (Element element : elements) { String url = urlPrefix + element.select("css").attr("href"); ...... }crawler-search-web:頁(yè)面模塊
頁(yè)面模塊是使用SpringBoot啟動(dòng)的模塊. 該模塊功能非常簡(jiǎn)單:
提供一個(gè)靜態(tài)頁(yè)面
提供一個(gè)搜索API
這里使用Spring MVC來(lái)提供實(shí)現(xiàn):
@Controller public class WelcomeController { @Autowired private MailService mailService; @RequestMapping("/") public String welcome() { return "welcome";//提供靜態(tài)頁(yè)面 } @RequestMapping("/search") @ResponseBody public Pagesearch(String keyword) { Pageable query = new PageRequest(0, 100);//提供一個(gè)搜索API return mailService.search(keyword, query); } }
有了Controller和頁(yè)面, 剩下的工作就是利用Spring Boot來(lái)啟動(dòng)工程了. 使用Spring Boot啟動(dòng)應(yīng)用非常方便, 只需幾行代碼:
@SpringBootApplication(scanBasePackages = { "org.ybak.crawler.persistence.service", "org.ybak.crawler.web" }) @EnableJpaRepositories("org.ybak.crawler.persistence.repo") @EntityScan("org.ybak.crawler.persistence.vo") public class WebApplication { public static void main(String[] args) throws Exception { SpringApplication.run(WebApplication.class, args); } }
有了Spring Boot的啟動(dòng)類, 只用運(yùn)行main就可以啟動(dòng)應(yīng)用了. 最后的頁(yè)面是這樣的:
應(yīng)用啟動(dòng)報(bào)錯(cuò), 提示"Service not found."
因?yàn)镾pring Boot默認(rèn)會(huì)掃描啟動(dòng)類所在包(org.ybak.crawler.web)下的Spring注解.但我的Service類在另外一個(gè)包:org.ybak.crawler.persistence.service, 所以Spring啟動(dòng)時(shí)沒(méi)有將service初始化. 解決的方法很簡(jiǎn)單. 參照上面的WebApplication代碼中scanBasePackages設(shè)置, 制定掃描的包列表即可.
應(yīng)用啟動(dòng)報(bào)錯(cuò), 提示"Repository not found."
和之前的問(wèn)題類似, 需要通過(guò)EnableJpaRepositories指定repo的掃描路徑.
應(yīng)用啟動(dòng)報(bào)錯(cuò),提示"Entity not found."
和之前的問(wèn)題類似, 需要通過(guò)EntityScan指定Entity的掃描路徑.
使用SpringBoot開(kāi)發(fā)時(shí), 頁(yè)面模板文件修改后瀏覽器不生效, Java邏輯修改后不生效.
引入spring-boot-devtools,該模塊可在調(diào)試時(shí)設(shè)置各種禁止模板緩存的配置, 方便開(kāi)發(fā)調(diào)試.
使用了SpringBootDevtools開(kāi)發(fā)時(shí), 任何文件修改都會(huì)導(dǎo)致SpringBoot重啟. 影響開(kāi)發(fā)效率.
devtools通過(guò)重啟來(lái)加載新類,讓新代碼生效. 但沒(méi)完沒(méi)了的重啟也會(huì)降低開(kāi)發(fā)效率.幸好spring提供了spring-loaded工具, 可以理解為開(kāi)源的針對(duì)spring的JRebel. 使用了它以后, 就可以享受無(wú)重啟熱部署了.
通過(guò)使用Spring Boot來(lái)快速實(shí)現(xiàn)一個(gè)web應(yīng)用, 確實(shí)感受到它的方便. 大量約定的默認(rèn)配置能讓代碼簡(jiǎn)潔不少, 但當(dāng)需要自定義配置時(shí), 面對(duì)spring-boot凌亂的文檔, 有著實(shí)讓人頭大. 必須經(jīng)常google才能解決不斷冒出的問(wèn)題.
另一方面, 使用Spring Boot開(kāi)發(fā)一個(gè)簡(jiǎn)單的Web應(yīng)用,并不能展示Spring Boot作為微服務(wù)開(kāi)發(fā)框架的威力. 后續(xù)我將調(diào)整這個(gè)web應(yīng)用的架構(gòu), 配以docker+ elasticsearch, 來(lái)實(shí)現(xiàn)這個(gè)應(yīng)用的微服務(wù)化.
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/65970.html
摘要:市長(zhǎng)信箱郵件查詢服務(wù)將應(yīng)用部署到在上一章我完成了將部署到的工作和都具有能快速啟動(dòng)的特性因此是一對(duì)用來(lái)部署微服務(wù)的黃金搭檔在計(jì)劃中基于的應(yīng)用也將部署到之上那我們就開(kāi)始行動(dòng)吧將部署到上需要執(zhí)行以下步驟保證打包后的可執(zhí)行能正常啟動(dòng)在應(yīng)用中編寫鏡像 市長(zhǎng)信箱郵件查詢服務(wù): 將SpringBoot應(yīng)用部署到Docker 在上一章, 我完成了將ES部署到Docker的工作. SpringBoot和...
摘要:集成上服務(wù)在我的應(yīng)用中希望能使用一些的特性比如這樣的數(shù)據(jù)結(jié)構(gòu)如果能方便的在開(kāi)發(fā)環(huán)境中使用起來(lái)就好了如何集成呢這里依然使用和來(lái)幫忙通過(guò)使用我們就能快速的部署好服務(wù)而通過(guò)使用我們能快速的把集成進(jìn)我們的服務(wù)并能使用提供的模板方法方便的調(diào)用的使用快 SpringBoot集成Docker上Redis服務(wù) 在我的應(yīng)用中, 希望能使用一些redis的特性:比如zset這樣的數(shù)據(jù)結(jié)構(gòu),如果能方便的在開(kāi)...
閱讀 1250·2021-11-23 09:51
閱讀 687·2021-11-19 09:40
閱讀 1353·2021-10-11 10:58
閱讀 2362·2021-09-30 09:47
閱讀 3739·2021-09-22 15:55
閱讀 2174·2021-09-03 10:49
閱讀 1266·2021-09-03 10:33
閱讀 707·2019-08-29 17:12