成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

市長(zhǎng)信箱郵件查詢服務(wù): 使用SpringBoot構(gòu)建工程

supernavy / 1565人閱讀

摘要:市長(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)如下:

抓取郵件信息是的DB操作

這里我使用的rxjava-jdbc來(lái)進(jìn)行數(shù)據(jù)的插入.相比JPA, rxjava-jdbc如果做基礎(chǔ)的查詢和插入操作使用起來(lái)很方便.

// 查詢郵件詳情url
Iterable> 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();
WEB展示的DB操作

查詢數(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 Page search(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è)面是這樣的:

踩過(guò)的坑

應(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ú)重啟熱部署了.

總結(jié)

通過(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

相關(guān)文章

  • 市長(zhǎng)信箱郵件查詢服務(wù): 將SpringBoot應(yīng)用部署到Docker

    摘要:市長(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和...

    SKYZACK 評(píng)論0 收藏0
  • 市長(zhǎng)信箱郵件查詢服務(wù): SpringBoot集成Docker上Redis服務(wù)

    摘要:集成上服務(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)...

    lanffy 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<