Git+Maven+Intellij+SpringMVC構(gòu)建簡單項(xiàng)目(下)

1. 創(chuàng)建數(shù)據(jù)庫和表

在小節(jié)UID替換器的實(shí)現(xiàn)中,我們設(shè)計(jì)了一個表。這部分就按照這個表實(shí)現(xiàn)CRUD,表情況如下:

--- table idmapper
id int 規(guī)則ID 自增
name varchar 規(guī)則名
source_id varchar 源ID
direct_id varchar 目的ID
enable int 是否啟用 0:不啟用鼓鲁,1:啟用

這里面數(shù)據(jù)庫采用通用的MySQL數(shù)據(jù)庫,先在MySQL中創(chuàng)建一個名為springdemo的數(shù)據(jù)庫:

CREATE DATABASE springdemo DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;

Intellij提供了專門的數(shù)據(jù)庫管理插件港谊,這是界面:

數(shù)據(jù)庫界面

接下來既可以用Intellij提供的數(shù)據(jù)庫工具創(chuàng)建idmapper表骇吭,又可以用SQL創(chuàng)建語句來處理,這里直接使用創(chuàng)建語句創(chuàng)建歧寺。

create table id_mapper(
  id INT NOT NULL AUTO_INCREMENT,
  name VARBINARY(255) NOT NULL,
  source_id VARBINARY(255) NOT NULL,
  direct_id VARBINARY(255) NOT NULL,
  enable INT DEFAULT 1,
  PRIMARY KEY (id)
);

運(yùn)行后的結(jié)果是:

運(yùn)行結(jié)果界面

往數(shù)據(jù)庫里面插入兩條數(shù)據(jù)用于測試燥狰,看看結(jié)果:

數(shù)據(jù)庫數(shù)據(jù)

目前數(shù)據(jù)沒有啥問題了,我們開始按照常用的SpringMVC方法開發(fā)我們的應(yīng)用斜筐。

2. Pojo 對象

由于不使用ORM框架(Mybatis或Hibernate)龙致,我們自己使用簡單的SQL來處理數(shù)據(jù)的CRUD,就需要定義一個Pojo類顷链,同數(shù)據(jù)庫中的表定義對應(yīng)目代。這個類的對象與表中每一行數(shù)據(jù)對應(yīng)。定義這個Pojo類如下:

public class IdMapper {

    private int id;
    private String name;
    private String sourceId;
    private String directId;
    /**
     * enable 狀態(tài)
     * 0 表示停用
     * 1 表示開啟
     */
    private int enable;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSourceId() {
        return sourceId;
    }

    public void setSourceId(String sourceId) {
        this.sourceId = sourceId;
    }

    public String getDirectId() {
        return directId;
    }

    public void setDirectId(String directId) {
        this.directId = directId;
    }

    public boolean getEnable() {
        return enable==1;
    }

    public void setEnable(boolean enable) {
        this.enable = enable?1:0;
    }

}

3. Pojo對象操作類

有了Pojo對象之后,我們需要實(shí)現(xiàn)這個Pojo對象的操作類像啼。如果用的是Python,使用Sqlalchemy或Django自己的ORM潭苞,然后定義類似的Pojo類就能夠自動實(shí)現(xiàn)對Pojo對象的查詢忽冻。但是Java這方面的功能我還不清楚,應(yīng)該是沒有這么好用的功能此疹,主要原因是Java是靜態(tài)語言僧诚,而這些功能是動態(tài)運(yùn)行時生成的,例如查詢方法蝗碎,像Python和Ruby這樣的腳本語言能夠做到湖笨,而靜態(tài)語言就不容易做到了。

Java的話蹦骑,此處就直接實(shí)現(xiàn)Pojo對象的操作類慈省。按照面向接口編程的原則,我們先設(shè)計(jì)一個IdMapperDao的接口眠菇,如下:

public interface IdMapperDao {

    int insert(final IdMapper idMapper);
 
 IdMapper get(int id);

    int update(final IdMapper idMapper);

    int delete(int id);

}

然后實(shí)現(xiàn)這個接口:


public class IdMapperDaoImpl  extends JdbcDaoSupport implements IdMapperDao {

    private final static Logger log=LoggerFactory.getLogger(IdMapperDaoImpl.class);

    public int insert(final IdMapper idMapper) {
        String sql="insert into idmapper(name, source_id, direct_id, enable) value(?, ?, ?, ?)";
        log.info("IdMapperDao insert:" + idMapper.toString());
        return this.getJdbcTemplate().update(sql, new PreparedStatementSetter() {
            @Override
            public void setValues(PreparedStatement ps) throws SQLException {
                ps.setString(1, idMapper.getName());
                ps.setString(2, idMapper.getSourceId());
                ps.setString(3, idMapper.getDirectId());
                ps.setInt(4, idMapper.getEnable()?1:0);
            }
        });
    }

   @Override
    public IdMapper get(int id) {
        String sql="select * from idmapper where id="+id;
        List<IdMapper> list = this.getJdbcTemplate().query(sql, new RowMapper<IdMapper>() {
            @Override
            public IdMapper mapRow(ResultSet rs, int rowNum) throws SQLException {
                return mapRowToIdMapper(rs);
            }
        });
        if(null == list || list.size() == 0) {
            return null;
        }
        return list.get(0);
    }

    private IdMapper mapRowToIdMapper(ResultSet rs) throws SQLException{
        IdMapper idMapper = new IdMapper();
        idMapper.setId(rs.getInt("id"));
        idMapper.setName(rs.getString("name"));
        idMapper.setSourceId(rs.getString("source_id"));
        idMapper.setDirectId(rs.getString("direct_id"));
        idMapper.setEnable(rs.getInt("enable")==1);
        return idMapper;
    }

    @Override
    public int update(final IdMapper idMapper) {
        //TODO
        return 0;
    }

    @Override
    public int delete(int id) {
        //TODO
        return 0;
    }

}

該類繼承了Spring的JdbcDaoSupport類边败,這能夠使得與MySQL數(shù)據(jù)庫進(jìn)行數(shù)據(jù)交互的代碼簡單易寫。我們寫好了IdMapper的操作類捎废,但是并沒有把它關(guān)聯(lián)到數(shù)據(jù)庫笑窜。我們在applicationContext.xml中進(jìn)行配置,如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="mysqlSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url" value="${mysql.db.url}?useUnicode=true&amp;characterEncoding=UTF-8&amp;failOverReadOnly=false&amp;autoReconnect=true" />
        <property name="username" value="${mysql.db.user}" />
        <property name="password" value="${mysql.db.pwd}" />
        <property name="removeAbandoned" value="true"/>
        <property name= "testWhileIdle" value="false" />
        <property name= "testOnBorrow" value="true" />
        <property name= "testOnReturn" value="false" />
        <property name= "validationQuery" value="select 1" />
    </bean>
    
    <bean id="idMapperDao" class="com.chenyi.learn.dao.impl.IdMapperDaoImpl">
        <property name="dataSource" ref="mysqlSource" />
    </bean>
    
</beans>

Spring容器在創(chuàng)建時會根據(jù)applicationContext.xml中的配置創(chuàng)建Bean登疗。我們設(shè)置的idMapperDao就是一個Bean排截,其有一個dataSource屬性指向mysqlSource的Bean,也就是說把mysqlSource的Bean注入到idMapperDao這個Bean中辐益。而在mysqlSource的Bean里面我們配置了數(shù)據(jù)庫的鏈接參數(shù)断傲。這里面我們需要了解的是,IdMapperDaoImpl類中并沒有dataSource這樣的屬性智政,那么是怎么樣實(shí)現(xiàn)注入的呢艳悔?這個問題要源自它的父類JdbcDaoSupport,查看這個類的源代碼女仰,我們可以發(fā)現(xiàn):

    /**
     * Set the JDBC DataSource to be used by this DAO.
     */
    public final void setDataSource(DataSource dataSource) {
        if (this.jdbcTemplate == null || dataSource != this.jdbcTemplate.getDataSource()) {
            this.jdbcTemplate = createJdbcTemplate(dataSource);
            initTemplateConfig();
        }
    }

所以猜年,應(yīng)該是通過set方法實(shí)現(xiàn)注入的。

這里面要談一下面向接口編程的好處疾忍。在這里我們提供了Dao的接口乔外,并給了一個實(shí)現(xiàn)類。假設(shè)有一天我們發(fā)現(xiàn)我們存儲的數(shù)據(jù)量已經(jīng)很大了一罩,MySQL的查詢已經(jīng)非常吃力了杨幼。這時候我們考慮使用NoSQL的數(shù)據(jù)庫,例如MongoDB,Hbase等差购。假如之前我們我們沒有用接口四瘫,而是直接寫了一個IdMapperDaoImpl類,而在很多其他代碼里面欲逃,我們直接用了這個類及其對象找蜜。這時候我們要創(chuàng)建一個新的操作類,假設(shè)為IdMapperHbaseDaoImpl稳析,并且我們不得不去修改其他的代碼中的實(shí)現(xiàn)洗做,把IdMapperDaoImpl都替換成IdMapperHbaseDaoImpl---這會造成很多問題。這種情況就是強(qiáng)依賴彰居。而面向接口編程就能做到弱依賴诚纸,解藕。

同樣是上面的情景陈惰,我們這里實(shí)現(xiàn)了一個IdMapperDao的接口畦徘,并在applicationContext.xml中為這個接口創(chuàng)建了一個Bean。而在其他的代碼里面抬闯,我們依賴接口旧烧,不依賴具體實(shí)現(xiàn)類,使用接口來操作画髓。例如會是以下代碼:

@Autowired
private IdMapperDao dao;

這樣Spring會把實(shí)現(xiàn)了IdMapperDao接口的類注入掘剪,也就是applicationContext.xml中配置的Bean。然后假設(shè)我們這次要使用IdMapperHbaseDaoImpl了奈虾,在這里只需要把對應(yīng)的Bean改成IdMapperHbaseDaoImpl就行了夺谁,代碼其他部分完全不用更改。這樣肉微,是不是很好啦匾鸥?這就是面向接口編程的優(yōu)勢,我們甚至只需要更改一行配置代碼碉纳,就能換掉底層的DAO具體實(shí)現(xiàn)勿负,而其他部分完全不用更改。

4. Service對象

按照J(rèn)ava Web的開發(fā)方法劳曹,一般來說會對業(yè)務(wù)邏輯進(jìn)行封裝奴愉,而這一層一般叫做service。至于為什么要用service進(jìn)行封裝铁孵,這可以寫很多東西了锭硼。但是此處我們直接按照常用的辦法來,先創(chuàng)建一個Service服務(wù)接口IdMapperService

public interface IdMapperService {

    IdMapper get(int id);
    int insert(IdMapper idMapper);
    // Other ...TODO

}

再實(shí)現(xiàn)這個接口IdMapperServiceImpl

@Service
public class IdMapperServiceImpl implements IdMapperService {

    @Autowired
    private IdMapperDao dao;

    @Override
    public IdMapper get(int id) {
        return dao.get(id);
    }
    
    @Override
    public int insert(IdMapper idMapper) {
        return dao.insert(idMapper);
    }
    
}

注意到實(shí)現(xiàn)代碼中使用了@Service注解蜕劝。這個注解能夠告訴Spring檀头,將為這個類創(chuàng)建一個Bean轰异。另外這段代碼中還使用了@Autowired注解實(shí)現(xiàn)自動裝配IdMapperDao對象,這里面體現(xiàn)了前面說的面向接口編程方法暑始,變量daoIdMapper接口類型搭独,具體對象由@Autowired裝配我們在xml中配置的Bean。Service實(shí)現(xiàn)里面很簡單廊镜,就做個演示牙肝,而一般常見的業(yè)務(wù)里面,Service是相當(dāng)復(fù)雜的期升,例如使用Service封裝事務(wù)。

5. Controller

終于到了最后一步Controller互躬,我們自定義一個IdMapperController

@Controller
@RequestMapping("/mapper")
public class IdMapperController {

    @Autowired
    private IdMapperService service;

    @RequestMapping("get")
    @ResponseBody
    public IdMapper get(@RequestParam int id) {
        return service.get(id);
    }

}

寫了一個簡單的Controller代碼播赁,主要通過id獲取IdMapper對像。然后我們通過本地測試和URL訪問吼渡,得到下面的結(jié)果:

返回Json

解釋一下這部分代碼容为。@Controller注解會告訴Spring也要為這個類生成Bean。@RequestMapping("/mapper")告訴Spring該類的訪問URL注冊到/mapper寺酪。而在這個控制器類中坎背,我們用自動注入的方法注入了Service對像。不像在Service中注入DAO的方式一樣---我們在xml聲明DAO的Bean寄雀,卻沒有在xml中聲明Service的Bean得滤,原因是Service的代碼我們使用了@Service注解,它會自動為Service生成Bean盒犹,就無需在xml中配置了懂更。

@ResponseBody注解會將返回對象解析成json格式急膀,這也是我們在瀏覽器中請求沮协,最后會返回json的緣故卓嫂。@RequestParam注解會將請求URL中的參數(shù)匹配到函數(shù)中的參數(shù),也就是說我們無需寫request.getAttribute("id")晨雳,就能直接獲取參數(shù)id的值行瑞,這個注解幫助我們搞定這些功能。只能說有了Spring AOP蘑辑,真是方便多了坠宴。

6. 總結(jié)

前前后后花了三個周末的下午總算完成了這三篇練習(xí)洋魂。作為一個剛?cè)隞ava Web坑的 Pythonista,感覺Java文化真是博大精深。語言的不同特征副砍,其相關(guān)技術(shù)棧也很不一樣的衔肢。例如這個小項(xiàng)目角骤,用Python的話心剥,使用Flask框架再加上sqlalchemy插件,一個小時內(nèi)就能弄出來优烧,但是用Java的話……

無意批評Java語言,Java的世界很有趣又沾,我現(xiàn)在領(lǐng)略不深熙卡,以后我會更深入學(xué)習(xí),不限于語言滑燃,技術(shù)棧颓鲜,構(gòu)建方法,框架灾杰,有趣的開源項(xiàng)目……當(dāng)然艳吠,Python我也會繼續(xù)學(xué)習(xí),動態(tài)腳本語言在某些方面優(yōu)勢實(shí)在是明顯的昭娩,更不用說Python這陣子在機(jī)器學(xué)習(xí)栏渺,數(shù)據(jù)分析領(lǐng)域的火熱啦】恼铮總之纹腌,要掌握一門面對對象的語言(Java)升薯,也要掌握好腳本語言(Python/Shell/Js)击困,熟練掌握編程語言這工具,做起事情來才得心應(yīng)手蛛枚。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末脸哀,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子白筹,更是在濱河造成了極大的恐慌谅摄,老刑警劉巖系馆,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件由蘑,死亡現(xiàn)場離奇詭異,居然都是意外死亡爷狈,警方通過查閱死者的電腦和手機(jī)裳擎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進(jìn)店門鹿响,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人惶我,你說我怎么就攤上這事绸贡∫慊” “怎么了结洼?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蒸殿。 經(jīng)常有香客問我鸣峭,道長,這世上最難降的妖魔是什么爬骤? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任霞玄,我火速辦了婚禮拉岁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘喊暖。我一直安慰自己陵叽,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布偏序。 她就那樣靜靜地躺著胖替,像睡著了一般。 火紅的嫁衣襯著肌膚如雪殉摔。 梳的紋絲不亂的頭發(fā)上记焊,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天,我揣著相機(jī)與錄音碗硬,去河邊找鬼。 笑死弛说,一個胖子當(dāng)著我的面吹牛翰意,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播醒第,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼稠曼,長吁一口氣:“原來是場噩夢啊……” “哼客年!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起司恳,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤榔至,失蹤者是張志新(化名)和其女友劉穎唧取,沒想到半個月后划提,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鹏往,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年韩容,在試婚紗的時候發(fā)現(xiàn)自己被綠了群凶。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片哄辣。...
    茶點(diǎn)故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖毅弧,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情寸宵,我是刑警寧澤元咙,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布蛾坯,位于F島的核電站,受9級特大地震影響脉课,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜唱遭,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一拷泽、第九天 我趴在偏房一處隱蔽的房頂上張望袖瞻。 院中可真熱鬧,春花似錦聋迎、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽伟葫。三九已至,卻和暖如春奶卓,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背夺姑。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工盏浙, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人废膘。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓丐黄,卻偏偏與公主長得像,于是被迫代替她去往敵國和親艰争。 傳聞我的和親對象是個殘疾皇子桂对,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評論 2 354

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理蕉斜,服務(wù)發(fā)現(xiàn),斷路器宅此,智...
    卡卡羅2017閱讀 134,656評論 18 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,810評論 6 342
  • 文章作者:Tyan博客:noahsnail.com 3.4 Dependencies A typical ente...
    SnailTyan閱讀 4,159評論 2 7
  • 龍紋繡霓裳毡熏, 溢塵冷宮香侣诵。 顏色隨花去狱窘, 不知是武皇蘸炸。
    玉木YUMU閱讀 114評論 0 0
  • 我辭職了,但突然想說點(diǎn)什么馁菜。 從去年九月份到現(xiàn)在(五月中旬),我想過辭職不下于三次峭火,十月智嚷,十一月,年后…… 之前的...
    沒什么特殊癖好閱讀 288評論 0 1