造一個方形的輪子10--集成第三方

造一個方形輪子文章目錄:造一個方形的輪子

01议双、解決遺留問題

這一篇沒有太多的解決上一篇遺留的問題痘番,靜態(tài)文件暫時沒有處理捉片,繼續(xù)算做遺留問題平痰,處理了一下Square框架的依賴汞舱,修改了mysql數(shù)據(jù)庫驅(qū)動的scope配置:

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
            <scope>provided</scope>
        </dependency>

02、集成Mybatis

集成第三方宗雇,找了一個比較常用的框架昂芜,持久層的Mybatis,起初覺得這東西用起來很方便赔蒲,沒有太細(xì)的考慮過泌神,如果要集成他要怎么做,一上手寫還是發(fā)現(xiàn)了很多問題舞虱。

集成的大體思路是:

1欢际、添加square-mybatis項目,做成依賴矾兜,處理Mybatis的相關(guān)配置

2损趋、demo項目添加Mybatis和square-mybatis依賴

3、添加mapper的xml配置及對應(yīng)的接口

4椅寺、關(guān)聯(lián)使Mybatis框架生效

這里有幾個問題:

1浑槽、square-mybatis里的代碼如果在square框架里加載(因為有Bean操作)

2、Mybatis的mapper.xml文件放在哪返帕?如何加載桐玻?

3、打包后怎么保證Mybatis框架生效

這幾個問題其實是做之前有大體思路荆萤,但做下來發(fā)現(xiàn)有些跟寫之前想的確實不一樣镊靴,下邊我會盡量記錄一下遇到的問題,及解決過程

03观腊、square框架加載square-mybatis

最開始我在square框架里添加了一個@config 注解及一個SquareConfig.java邑闲,作用就是使用這個注解標(biāo)記的 類同時繼承SquareConfig接口,實現(xiàn)config()方法梧油,會在square框架加載過程中處理依賴之前苫耸,執(zhí)行這個config()方法,目的是把配置的Mybatis框架的Mapper注入到Bean容器中儡陨,好在接下來的initDI()方法中使用褪子,保證依賴類的存在,但是寫完后發(fā)現(xiàn)因為這個類在 square-mybatis項目里骗村,是以依賴的形式提供給demo的嫌褪,所以demo項目啟動過程中掃描不到j(luò)ar包里的文件。

所以最終將square-mybatis中的Conifg類實現(xiàn)成了靜態(tài)方法胚股,在demo中添加了InitConfig.java來實現(xiàn)調(diào)用功能笼痛,下邊看代碼:

square-mybatis項目的MybatisConfig.java:

package com.jisuye;
//import ...
/**
 * 集成Mybatis配置類
 * @author ixx
 * @date 2019-09-08
 */
public class MybatisConfig {
    private static Logger logger = LoggerFactory.getLogger(MybatisConfig.class);
    public static void init(){
        // 獲取DataSource
        DataSource dataSource = DbUtil.getDataSource();
        // 使用代碼構(gòu)造Mybatis配置
        TransactionFactory transactionFactory = new JdbcTransactionFactory();
        Environment environment = new Environment("development", transactionFactory, dataSource);
        Configuration configuration = new Configuration(environment);
        URL mapperUrl = ClassLoader.getSystemResource("mapper/");
        String path = mapperUrl.getPath();
        logger.info("mapperUrl path :{}", path);
        // 判斷當(dāng)前啟動是在否jar包中
        if(path.indexOf("!/")>0){
            getXmlByJar(path, configuration);
        } else {
            getXmlByFile(path, configuration);
        }
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
        try {
            SqlSession session = sqlSessionFactory.openSession();
            // 循環(huán)所有Bean處理Config
            for(Class clzz : BeansMap.getClassList()) {
                Annotation[] annotations = clzz.getAnnotations();
                for (Annotation annotaion : annotations) {
                    // 如果是Mybatis的Mapper則注入到容器里
                    if(annotaion instanceof Mapper){
                        Object mapper = session.getMapper(clzz);
                        BeanObject tmpBeanObject = new BeanObject(clzz, mapper);
                        tmpBeanObject.setObject(mapper);
                        BeansMap.put(clzz.getName(), tmpBeanObject);
                    }
                }
            }
        } catch (Exception e){
            logger.error("init mybatis config error!!", e);
        }
    }

    /**
     * 本地調(diào)試獲取xml配置文件
     * @param path
     * @param configuration
     */
    private static void getXmlByFile(String path, Configuration configuration){
        File mapperDir = null;
        try {
            mapperDir = new File(path);
            if(mapperDir.exists()){
                File[] files = mapperDir.listFiles();
                logger.info("files size :{}", files.length);
                for (File file : files) {
                    logger.info("file path:{}", file.getPath());
                    logger.info("file abspath:{}", file.getAbsolutePath());
                    try {
                        XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(
                                new FileInputStream(file), configuration,
                                file.getPath(),
                                configuration.getSqlFragments());
                        xmlMapperBuilder.parse();
                    } catch (Exception e) {
                        e.printStackTrace(); // 出現(xiàn)錯誤拋出異常
                    }
                }
            }
        } catch (Exception e) {
            logger.error("load mapper xml file error!", e);
        }
    }

    /**
     * 處理jar包中的xml配置文件(打包后啟動)
     */
    private static void getXmlByJar(String path, Configuration configuration){
        logger.info("xml get by path:{}", path);
        path = path.substring(0, path.indexOf("!/")).replace("file:", "");
        logger.info("xml get by jar path:{}", path);
        try {
            JarFile jarFile = new JarFile(path);
            Enumeration<JarEntry> jarEntryEnumeration = jarFile.entries();
            while (jarEntryEnumeration.hasMoreElements()){
                JarEntry jarEntry = jarEntryEnumeration.nextElement();
                String name = jarEntry.getName();
                // logger.info("file name ====={}", name);
                if(name.startsWith("mapper/") && name.endsWith(".xml")){
                    XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(
                            ClassLoader.getSystemResourceAsStream(name), configuration,
                            name,
                            configuration.getSqlFragments());
                    xmlMapperBuilder.parse();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

這個類處理時遇到的問題比較多,首先最開始沒找到設(shè)置mapper.xml文件的地方,就用了Mybatis默認(rèn)的mapper.xml跟對應(yīng)的接口在同一個目錄下缨伊,結(jié)果發(fā)現(xiàn)這樣需要在pom文件中配置resource引入.xml文件 不然編譯后找不到xml文件摘刑,而且還要添加一個配置,指定Mybatis掃描的package路徑.后來翻看了mybatis-spring的代碼找到了遍歷加載xml配置文件的方法刻坊,又遇到打包后在jar包里加載不到的問題枷恕,好在之前處理打包插件,弄過jar文件谭胚,直接在做個判斷如果在jar里啟動的徐块,特殊處理一下,最后就可以了灾而。

04胡控、square項目調(diào)整

添加Config相關(guān)注解及接口:

package com.jisuye.annotations;
/**
 * Config注解
 * @author ixx
 * @date 2019-09-06
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Config {
     String value() default "";
}
package com.jisuye.core;
/**
 * 定義config接口,使用@config注解的類需要繼承
 * @author ixx
 * @date 2019-09-08
 */
public interface SquareConfig {
    void config();
}

BeanInitUtil.java添加initConfig()方法:

        //...
        public static void init(Class clazz){
        String path = clazz.getResource("").getPath();
        // ....
        // 處理aop類
        initAop();
        // 處理config
        initConfig();
        // 處理依賴注入
        initDI();
    }
        private static void initConfig(){
        // 循環(huán)所有Bean處理Config
        Set<String> keySet = BeansMap.keySet();
        String[] keys = new String[keySet.size()];
        keySet.toArray(keys);
        List<Object> list = new ArrayList<>();
        for (String key : keys) {
            BeanObject beanObject = BeansMap.get(key);
            if(list.contains(beanObject)){
                continue;
            }
            list.add(beanObject);
            for (Annotation annotaion : beanObject.getAnnotaions()) {
                // 如果是配置則調(diào)用config()方法
                if(annotaion instanceof Config){
                    try {
                        Method method = beanObject.getBeanClass().getMethod("config");
                        method.invoke(beanObject.getObject());
                    } catch (Exception e) {
                        log.error("execute config method error!!", e);
                    }
                }
            }
        }
    }
        //...

DbUtil原來只有自己使用旁趟,現(xiàn)在集成Mybatis后獲取 DataSource部分可以放在這個類里铜犬,于是添加了一個dataSource 參數(shù),及對應(yīng)的getDataSource()方法轻庆,首次調(diào)用如果為空會去初始化:

package com.jisuye.util;
// import ...
/**
 * 數(shù)據(jù)庫操作工具
 * @author ixx
 * @date 2019-07-01
 */
public class DbUtil {
    private static final Logger log = LoggerFactory.getLogger(DbUtil.class);
    private static Connection connection;
    private static DataSource dataSource;

    /** 初始化方法*/
    public static void init(){
        try {
            //...
            HikariDataSource ds = new HikariDataSource();
            //...
            connection = ds.getConnection();
            dataSource = ds;
        } catch (Exception e) {
            log.error("mysql connection init error..", e);
            throw new SquareException("mysql connection init error....");
        }
    }

    // ...
    public static DataSource getDataSource(){
        if (dataSource == null) {
            init();
        }
        return dataSource;
    }
}

05癣猾、修改square-demo項目,測試集成

首先添加pom依賴:

                <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.2</version>
        </dependency>
        <dependency>
            <groupId>com.jisuye</groupId>
            <artifactId>square-mybatis</artifactId>
            <version>0.1-SNAPSHOT</version>
        </dependency>

添加InitConfig.java配置類余爆,只是用來調(diào)用MybatisConfig.init()方法纷宇。

package com.jisuye.config;
// import ...
@Config
public class InitConfig implements SquareConfig {
    @Override
    public void config() {
        MybatisConfig.init();
    }
}

添加AbcMapper.java接口

package com.jisuye.mapper;
//import ...
/**
 * 測試mapper
 */
@Mapper
public interface AbcMapper {
    List<AbcEntity> selectAbc(int id);
}

在resource下添加mapper目錄,添加AbcMapper.xml文件:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jisuye.mapper.AbcMapper">
    <resultMap id="abc" type="com.jisuye.entity.AbcEntity">
        <result column="id" javaType="Integer" property="id" />
        <result column="name" javaType="java.lang.String" property="name" />
        <result column="age" javaType="Integer" property="age" />
    </resultMap>
    <select id="selectAbc" resultMap="abc">
    select * from abc where id = #{id}
  </select>
</mapper>

application.yml中添加數(shù)據(jù)庫相關(guān)配置

server:
  port: 8765
  servlet:
    context-path: /square-demo
square:
  datasource:
    url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=false&autoReconnect=true
    username: root
    password: 123456

HelloController 添加調(diào)用Mapper的方法:

package com.jisuye.controller;
//import ...
@Controller("/")
public class HelloController {
    @Resource
    private AbcMapper abcMapper;
    @GetMapping("/id")
    public String selectAbc(@RequestParam("id") int id) {
        List<AbcEntity> list = abcMapper.selectAbc(id);
        if(list != null && list.size()>0){
            return "success! name is : " + list.get(0).getName();
        } else {
            return "error! select by db.";
        }
    }
    @GetMapping("/hello")
    public String hello(@RequestParam("name") String name){
        return "hello "+name;
    }
}

首先在IDE中啟動程序測試蛾方,程序啟動后訪問:http://localhost:8765/square-demo/id?id=1

返回結(jié)果:success! name is : ixx

查看日志輸出:

19:42:45.594 [http-nio-8765-exec-1] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction - Setting autocommit to false on JDBC Connection [HikariProxyConnection@2030223697 wrapping com.mysql.cj.jdbc.ConnectionImpl@d088afc]
19:42:45.604 [http-nio-8765-exec-1] DEBUG com.jisuye.mapper.AbcMapper.selectAbc - ==>  Preparing: select * from abc where id = ? 
19:42:45.643 [http-nio-8765-exec-1] DEBUG com.jisuye.mapper.AbcMapper.selectAbc - ==> Parameters: 1(Integer)
19:42:45.681 [http-nio-8765-exec-1] DEBUG com.jisuye.mapper.AbcMapper.selectAbc - <==      Total: 1
19:42:45.681 [http-nio-8765-exec-1] INFO com.jisuye.core.DispatcherServlet - exec method :selectAbc
19:42:45.681 [http-nio-8765-exec-1] INFO com.jisuye.core.DispatcherServlet - response:success! name is : ixx

ok !本地測試通過像捶,再試一下打包。

在square-demo目錄下執(zhí)行mvn clean package 構(gòu)建完畢后執(zhí)行java -jar target/square-demo-1.0-SNAPSHOT.jar

等程序啟動成功后訪問:http://localhost:8765/square-demo/id?id=1

返回結(jié)果:success! name is : ixx

控制臺也有上邊同樣的日志輸出桩砰,說明打包啟動也OK了拓春。

06、遺留問題

集成這篇還算完事吧亚隅,至少該實現(xiàn)的都實現(xiàn)了硼莽,當(dāng)然也相當(dāng)于會對Mybatis插件做了些定制如果集成其它的功能應(yīng)該還需要做一定的抽象工作。
上一篇遺留的最主要的問題就是靜態(tài)文件的問題了煮纵,不知道下一篇會不會解決懂鸵。。行疏。

本篇代碼地址: https://github.com/iuv/square/tree/square10
spring-mybatis地址: https://github.com/iuv/square-mybatis
演示項目地址: https://github.com/iuv/square-demo

本文作者: ixx
本文鏈接: http://jianpage.com/2019/09/09/square10
版權(quán)聲明: 本作品采用 知識共享署名-非商業(yè)性使用-相同方式共享 4.0 國際許可協(xié)議 進行許可匆光。轉(zhuǎn)載請注明出處!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末酿联,一起剝皮案震驚了整個濱河市终息,隨后出現(xiàn)的幾起案子夺巩,更是在濱河造成了極大的恐慌,老刑警劉巖周崭,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件劲够,死亡現(xiàn)場離奇詭異,居然都是意外死亡休傍,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進店門蹲姐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來磨取,“玉大人,你說我怎么就攤上這事柴墩∶ρ幔” “怎么了?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵江咳,是天一觀的道長逢净。 經(jīng)常有香客問我,道長歼指,這世上最難降的妖魔是什么爹土? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮踩身,結(jié)果婚禮上胀茵,老公的妹妹穿的比我還像新娘。我一直安慰自己挟阻,他們只是感情好琼娘,可當(dāng)我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著附鸽,像睡著了一般脱拼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上坷备,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天熄浓,我揣著相機與錄音,去河邊找鬼省撑。 笑死玉组,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的丁侄。 我是一名探鬼主播惯雳,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了洪灯?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤坎吻,失蹤者是張志新(化名)和其女友劉穎潮孽,沒想到半個月后揪荣,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡往史,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年仗颈,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片椎例。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡挨决,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出订歪,到底是詐尸還是另有隱情脖祈,我是刑警寧澤,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布刷晋,位于F島的核電站盖高,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏眼虱。R本人自食惡果不足惜喻奥,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望捏悬。 院中可真熱鬧映凳,春花似錦、人聲如沸邮破。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽抒和。三九已至矫渔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間摧莽,已是汗流浹背庙洼。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留镊辕,地道東北人油够。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像征懈,于是被迫代替她去往敵國和親石咬。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,955評論 2 355

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