
课程咨询: 400-996-5531 / 投诉建议: 400-111-8989
认真做教育 专心促就业
昆明IT培训的小编这一期给一期给大家讲Spring + SpringMVC + Druid + MyBatis给你一个灵活的后端解决方案。
1.方案整体一览
2.遇到的坑
生命不息,折腾不止。
折腾能遇到很多坑,填坑我理解为成长。
两个月前自己倒腾了一套用开源框架构建的JavaWeb后端解决方案。
Spring + SpringMVC + Druid + JPA(Hibernate impl)给你一个稳妥的后端解决方案
引入到项目组后经过几番打磨,现在也出落的有模有样。
最近将工程中的Hibernate换了换Mybatis试试,毕竟人都需要新鲜感。
我Hibernate接触的要比MyBatis早,作为最流行的两ORM框架,个人认为其中很多思想都相通。
但MyBatis特有的ResultMap构想,能进行更为细致的SQL调整和优化。
在开发社区、版本更新速度、支持的工具上,Hibernate比MyBatis更胜一筹。
项目Git地址:#/LanboEx/sdm
1.方案整体一览
由 Controller层接受前端参数并响应请求,携带数据跳转页面。
Controller层注入ServiceInter,ServiceImpl层组织业务数据。
ServiceImpl层注入Mybatis Mapper, Mapper进行数据的访问。
和Hibernate类似整个dao层,都可以由工具生成,工程中使用的是org.mybatis.generator插件。
web.xml
pom.xml
2.遇到的坑
浅坑这里就不说了,下面梳理比较深的几个坑。
如果你以前遇到过这些问题,并且有比我还完美的解决方法,请赐教。
a. MapperScannerConfigurer提前初始化导致spring注入配置文件失效
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property ame="basePackage" value="com.rambo.sdm.dao.inter"/>
<property ame="sqlSessionFactory " ref="sessionFactory"/>
</bean>
因为希望Spring能扫描Mapper接口类加载Mapper.xml并自动生成实现代理类,注入到相应的ServiceImpl中。
刚开始配置如上,但是发现Spring无法正常加载配置文件中的信息。
也就是用${jdbc.username}这样之类的表达式,无法获取到properties文件里的内容。
几次尝试未果之后,发现MapperScannerConigurer实际是在解析加载bean定义阶段,这个时候设置sqlSessionFactory的话。
会导致提前初始化一些类,PropertyPlaceholderConfigurer还没来得及替换定义中的变量,导致把表达式当作字符串复制了。
将sqlSessionFactory替换为sqlSessionFactoryBeanName问题解决,配置如下:
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property ame="basePackage" value="com.rambo.sdm.dao.inter"/>
<property ame="sqlSessionFactoryBeanName" value="sessionFactory"/>
</bean>
b. dao层数据表主键自动生成
在编写工程例子运行后,发现提示错误UUID不为NUll。
自动生成的mapper.xml中,对于主键(自增序列/uuid)需要自己配置,这点确实有点low。
自己配置就自己配置吧,mapper.xml中UUID配置如下:
<selectKey keyProperty="uuid" resultType="String" order="BEFORE">
select replace(uuid(),'-','') UUID
</selectKey>
假设项目推进中,生成数据表配置文件后需要研发手动在mapper.xml的新增方法中添加主键生成策略,不仅繁琐而且出问题的概率极大。
试着摸索有没有什么统一配置的地方,发现了一种但还是不够完美。统一配置在generatorConfig.xml生成表的地方:
<table tableName="user" domainObjectName="UserPO">
<generatedKey column="uuid" sqlStatement="SELECT REPLACE(UUID(),'-','') UUID FROM DUAL"/>
</table>
主键生成策略使用SQL语句这点,就注定Mybatis在数据库移植方面无法尽善尽美。
c. maven编译后未将xml文件编译到class文件夹下
工程中需要输出到编译目录的配置文件有两部分,各数据表mapper.xml和框架之间的各种各种的.xml/.properties。
编译运行时报错:org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)
说是未绑定?辗转半天,发现mapper.xml没有被编译到对应的文件夹下。
maven build --> resources节点下新增子resource子节点:
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
添加子节点后,mapper.xml确实编译到对应的文件夹下了,但工程中原Resources下的文件没有像以前一样编译到classes下。
maven build --> resources节点下继续新增子resource子节点后解决:
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
<filtering>true</filtering>
</resource>
d. jetty插件启动web项目时,会同时启动mybatis逆向工程插件
当使用jetty:run启动web项目后,总会有莫名其妙的问题。
报错君是这样的:java.lang.IllegalArgumentException: Result Maps collection already contains value for com.rambo.sdm.dao.inter.UserPOMapper.BaseResultMap
顺着启动日志发现,每次jetty:run时,mybatis.generator插件会先运行,并逆向数据库工程。
逆向生成就逆向生成吧,按道理需要生成的东西已经存在的话,跳过即可。
generator插件运行机制还是有点问题的,生成的类它跳过,但配置文件会将内容追加进去,所以才有了上述那个报错。
移除generator插件executions --> execution下goals子节点问题得以解决。
<executions>
<execution>
<id>Generate MyBatis Artifacts</id>
</execution>
</executions>
需要逆向工程时,手动启动插件即可。