造一個方形輪子文章目錄:造一個方形的輪子
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)載請注明出處!