spring+mybatis+mina+logback框架搭建

Posted 致梦想

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring+mybatis+mina+logback框架搭建相关的知识,希望对你有一定的参考价值。

第一次接触spring,之前从来没有学过spring,所以算是赶鸭子上架,花了差不多一个星期来搭建,中间遇到各种各样的问题,一度觉得这个框架搭建非常麻烦,没有一点技术含量,纯粹就是配置,很低级!但随着搭建的完成,有一点点体会:框架可以让我们的代码更加像一个项目,而不是一个普普通通的作业,这在之前我们学生时代往往不会注意到这一点。我觉得这就是专业和业余的区别。当然,目前,我连spring入门可能都算不上,只是为了完成任务来搭建这套框架,但还是很有收获的,所以记录下这篇博客,给过来人参考。

另外还有一个重要原因是,网上的框架搭建如spring+mybatis的博客,老实说,有很多明显有错误!最终竟然还能正确运行出结果,简直匪夷所思,还有的,缺少文件或者说明,会让刚学习spring的人摸不着头脑,尤其是你兴致勃勃地参考一篇博客,辛苦地搭建了一大半,结果到最后发现,有一个文件没有提供,有一个函数没有提供,有一个类没有提供。。。总之你无法继续下去,内心一定会非常奔溃!所以,我决定写这篇博客!

关于spring的介绍,我就不多说了,我也是门外汉~我就说一下,我为什么要使用这几个框架,spring自然不必多说,mybatis是对数据库的封装,用来操作数据库,mina是对网络通信(如socket)的封装,logback是关于日志的框架。我要实现的是一个短信平台的验证系统,需要操作数据库,需要通过向第三方服务器发送短信,这几个功能可以由这些框架一一实现。

参考博客:

http://chenjc-it.iteye.com/blog/1402939

http://www.cnblogs.com/nick-huang/p/3838326.html

mybatis

mybatis和spring整合需要的包有mybatis、mybatis-spring、数据库驱动包(oracle是ojdbcXXX.jar或者mysql,根据用到的数据库配置)和数据库连接池dbcp包。如果对数据库连接池不太清楚的,可以上网搜索。关于包的版本,我用的跟网上的一些也都不一样,所以大家也没必要纠结一定要用哪个版本的包,不过确实会存在版本过高或过低导致的问题,到时候注意一下就行了。包的下载,我强烈推荐一个网址:https://mvnrepository.com/,只要输入相关关键字就可以找到相应不同版本的包,非常方便!好了,现在开始搭建。假设,我已经用oracle创建了一个表-wkzf,表的字段有(telephone,starttime...),为了方便,我只列出这两个字段,这两个字段的类型都是NUMBER。telephone表示手机号,是11位,starttime表示发送短信的时间,它是毫秒,用来表示现在与 1970 年1月1日00:00:00.000的偏移量,这个可以很方便地计算一个验证码是否超过60秒,如果是日期如yy-mm-dd-hh这样的格式就不太好计算了。

接下来,我们创建一个包,包名可以叫作com.xysj.mybatis.entity,包名的规则可以参考:http://www.runoob.com/java/java-package.html。这些小细节可以让你看起来更加专业。在这个包下面,我们可以创建一个实体类,用来与上面我们设计的表中的字段对应起来,代码如下:

 1 package com.xysj.mybatis.entity
 2 
 3 public class User {
 4     private long telephone;
 5     private long starttime;
 6 
 7     public long getTelephone()
 8     public void setTelephone(long telephone)
 9     ...
10 }

可以看到,我们实体类User当中,有两个私有变量,很显然分别对应表中的两个字段,然后还有get和set函数,分别用来对这些变量进行操作。

接下来,我们定义一个接口类UserMapper,用来对数据库进行操作。同样,我们创建一个包:com.xysj.mybatis.mapper,在该包下面,创建一个java文件,代码如下:

1 package com.xysj.mybatis.mapper
2 
3 import com.xysj.mybatis.User
4 
5 public interface UserMapper {
6     public User selectUser(long telephone)
7     public void insertUser(User user)
8     ...
9 }

UserMapper只是一个接口类,那它的具体实现,即操作数据库的SQL语句在哪里呢?我们可以通过xml文件来进行配置,即具体的实现都写在xml文件当中。所以我们可以在整个工程的src目录下,创建一个UserMapper.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.xysj.mybatis.mapper.UserMapper">

    <select id="selectUser" resultType="user">
        select * from wkzf where telephone = #{telephone}
    </select>
    
    <insert id="insertUser" parameterType="user">
        insert into wkzf values(#{telephone},#{starttime})
    </insert>

</mapper>

需要注意的有几点:1)namespace后面填写的是包名+接口类名,一定不能错,错了,不像java有异常机制,可以捕捉异常,xml配置错了,很难发现,所以一定要小心!2)id后面的名字对应UserMapper.java中函数名,不能错!3)可能有人会疑问,为什么这里是“user”而不是“User”,我们定义的类是User啊,稍安勿躁,后面还有一个mybatis-configure.xml文件配置时,会对user进行说明,简单来说就是把User用了一个别名user。4)其他就是注意一些格式要求,#{}代表参数,对应着user中定义的变量。

ok,现在对mybatis-configure.xml文件进行说明,代码如下:

 1 <?xml version="1.0" encoding="UTF-8" ?>
 2 <!DOCTYPE configuration
 3   PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
 4   "http://mybatis.org/dtd/mybatis-3-config.dtd">
 5   
 6 <configuration>
 7 
 8     <!-- Register Alias -->
 9     <typeAliases>
10         <typeAlias alias="user" type="com.xysj.mybatis.entity.User" />
11     </typeAliases>
12 
13     <!-- Register Mapper -->
14     <mappers>
15         <!-- SQL Mapper -->
16         <mapper resource="UserMapper.xml" />
17     </mappers>
18     
19 </configuration>

可以看到,我们对User取了一个别名user,这样就不需要把User的包名全部都写上了。同时,我们还关联了上面刚刚定义的UserMapper.xml文件。如果是单独的使用mybatis,用不到spring框架,这个xml文件中还应该声明DataSource的相关信息,好让mybatis知道与那个数据库连接。不过有了spring之后,这部分可以在spring-configure.xml文件中声明。

接下来我们先创建一个包com.xysj.service,然后在包下创建一个UserService的类,代码如下:

 1 package com.xysj.service;
 2 
 3 import com.xysj.mybatis.entity.User;
 4 import org.mybatis.spring.SqlSessionTemplate;
 5 
 6 public class UserService {
 7     private SqlSessionTemplate  sqlSession;
 8     
 9     public SqlSessionTemplate getSqlSession() {
10         return sqlSession;
11     }
12 
13     public void setSqlSession(SqlSessionTemplate sqlSession) {
14         this.sqlSession = sqlSession;
15     }
16     
17     public UserInfo selectUser(long telephone) {
18           User user = null;
19           try {
20                  user = (User) sqlSession.selectOne("com.xysj.mybatis.mapper.UserMapper.selectUser", telephone);
21           } catch (Exception e) {
22                  e.printStackTrace();
23           }
24         
25           return user;
26     }
27 }

注意selectOne中的函数第一个参数,一定要写完整!包名+接口名+函数名。之前,我这边没怎么搞懂,代码老是出错,我调试了很久才搞定!当然,这里只写了一个函数,你可以自己写insertUser、updateUser等函数,都是类似的。

spring

好了,现在我们开始配置spring-configure.xml文件,这个非常关键,一点也不能错,代码如下:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3     default-autowire="byName"
 4     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 5     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
 6 
 7     <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
 8         <property name="driverClassName" value="oracle.jdbc.OracleDriver" />
 9         <property name="url" value="jdbc:oracle:thin:@localhost:1521:SID" />
10         <property name="username" value="xxxx" />
11         <property name="password" value="xxxx" />
12         <property name="maxActive" value="100"></property>
13         <property name="maxIdle" value="30"></property>
14         <property name="maxWait" value="500"></property>
15         <property name="defaultAutoCommit" value="true"></property>
16     </bean>
17     
18     <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
19         <property name="configLocation" value="mybatis-configure.xml"></property>
20         <property name="dataSource" ref="dataSource" />
21     </bean>
22     
23     <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
24         <constructor-arg index="0" ref="sqlSessionFactory" />
25     </bean>
26     
27     <bean id="userService" class="com.xysj.service.UserService">
28        <property name="sqlSession" ref="sqlSessionTemplate" />
29     </bean>
30 
31 </beans>

需要注意的有几点:1)关于数据源的配置,因为用到了dbcp数据库连接池,所以需要相应的库(commons-dbcp-1.2.jar和commons-pool-1.4.jar ),localhost代表本机,如果你是远程连接到某一个数据库服务器上,则写服务器的IP地址,1521是端口号,SID是数据库名,记住是数据库名,不是表名!2)configLocation后面的value值填写正确,是mybatis的xml配置文件。3)最后一个bean,即“userService”后面的class处写正确,包名+类名。差不多要注意就是这几点,可能还有遗漏的,等到发现了再说。

mina

因为我们只是调用第三方的短信发送平台,所以我们只需要写一个客户端就行,不需要写服务端。总共有4个文件,我们可以先创建一个包:com.xysj.mina。第一个文件ClientHandle.java:

 1 package com.xysj.mina;
 2 
 3 import ...
 4 
 5 public class ClientHandle extends IoHandlerAdapter {
 6     private final static Log log = LogFactory.getLog(ClientHandle.class);
 7     
 8     @Override
 9     public void messageReceived(iosession session, Object message) throws Exception {
10         log.debug("客户端收到消息" + message.toString());
11         super.messageReceived(session, message);
12     }
13     
14     @Override
15     public void messageSent(IoSession session, Object message) throws Exception {
16         log.debug("客户端发送消息" + message.toString());
17         super.messageSent(session, message);
18     }
19     
20     @Override
21     exceptionCaught
22     sessiogCreated
23     sessionOpened
24     sessionClosed
25     sessionIdle
26 }

因为我们公司是在云桌面开发的,所有的代码和开发环境都在思杰的云桌面上,没有办法拷贝下来,所以只能手打,错误在所难免啊~我也没有办法,import后面的内容省略了,一般你敲完代码,eclipse会提示需要import哪些类,一些重载的函数我也省略了,函数里的内容基本上都差不多,除了一些参数不一样。还有网上搜一下,也能找到这些函数的实现,这里我就不一一敲了。都是手工敲的,难免会有一些代码会敲错,如果出错,请大家指出来哈!第二个文件CodeFactory.java:

 1 package com.xysj.mina;
 2 
 3 import ...
 4 
 5 public class CodeFactory implements ProtocolCodecFactory {
 6     private XmlDecoder xmldecoder = null;
 7     private XmlEncoder xmlencoder = null;
 8     
 9     public CodeFactory() {
10         this(Charset.defaultCharset());
11     }
12     
13     public codeFactory(Charset charset) {
14         this.xmldecoder = new XmlDecoder(charset);
15         this.xmlencoder = new XmlEncoder(charset);
16     }
17     
18     @Override
19     public ProtocolDecoder getDecoder(IoSession session) throws Exception {
20         return xmldecoder
21     }
22     
23     @Override
24     public ProtocolEncoder getEncoder(IoSession session) throws Exception {
25         return xmlencoder
26     }
27 }

从字面意思不难发现,一个是编码,一个是解码,当你把消息发送出去前(即调用messageSent函数前),需要先编码。当你收到消息及messageReceived响应时,会先进行解码。所以接下来就是对这两部分分别进行实现,网上也有响应的代码,也可以参考,老实说mian这部分我也不是很清楚,正如我前面所说的,我只是先搭建了这么一个框架,然后把代码调通,以后有时间,再慢慢深入了解这些框架。好了,首先是XmlDecoder.java:

 1 package com.xysj.mina;
 2 
 3 import ...
 4 
 5 public class XmlDecoder extends CumulativeProtocolDecoder {
 6     private final static Log log = LogFactory.getLog(XmlDecoder.class);
 7     private final Charset charset;
 8     
 9     public XmlDecoder(Charset charset) {
10         this.charset = charset;
11     }
12     
13     @Override
14     protected boolean doDecode(IoSession session, IoBuffer in,
15             ProtocolDecoderOutput out) throws Exception {
16             CharsetDecoder decoder = charset.newDecoder();
17             IoBuffer ioBuffer = IoBuffer.allocate(3072).setAutoExpand(true);
18             log.info(“开始解码”);
19             
20             byte[] b = new byte[in.limit()];
21             in.get(b);
22             
23             Charset charset = Charset.forName("GBK");
24             ByteBuffer buf = ByteBuffer.wrap(b);
25             CharBuffer cbuf = charset.decoder(buf);
26             log.debug("客户端收到消息" + cbuf.toString());
27             
28             while(in.hasRemaining()) {
29                 byte bte = in.get();
30                 ioBuffer.put(bte);
31                 if(bte == \'\\n\') {
32                     ioBuffer.flip();
33                     byte[] bt = new byte[ioBuffer.limit()];
34                     ioBuffer.get(bt);
35                     String message = new String(bt, decoder.charset());
36                     ioBuffer = IoBuffer.allocate(100).setAutoExpand(true)limit
37                     out.write(message);
38                 }
39             }
40             return true;
41             }
42 }

有了解码的,还有编码的XmlEncode.java:

 1 package com.xysj.mina;
 2 
 3 import ...
 4 
 5 public class XmlEncoder extends ProtocolEncoderAdapter {
 6     
 7     private final Charset charset;
 8     
 9     public XmlEncoder(Charset charset) {
10         this.charset = charset;
11     }
12     
13     @Override
14     protected void encode(IoSession session, Object obj,
15             ProtocolEncoderOutput out) throws Exception {
16             CharsetEncoder encoder = charset.newEncoder();
17             IoBuffer io = IoBuffer.allocate(100).setAutoExpand(true);
18             
19             io.putString(obj.toString(), encoder);
20             io.put((byte)\'\\r\');
21             io.put((byte)\'\\n\');
22             io.flip();
23             out.write(io);
24     }
25 }

好了,关于mina的四个文件都已经写好了,关键是编码和解码的实现,感觉这是要按照相同的格式才行。如果要配置mina的服务器的话,还需要创建响应的xml配置文件,大家自己上网搜找。我们这里只涉及客户端的代码。

logback

日志框架,这个一句话说明就行了,相信大家看上面的代码看到这一行代码:private final static Log log = LogFactory.getLog(类名.class)。然后,在函数中,只要加上log.info()或者log.debug()就可以生成相应的日志。当然,生成的日志放在哪里,日志是什么样的格式,日志的名字等等信息都需要在logback的xml配置文件中声明,logback.xml文件如下:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <configuration debug="false">
 3 <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
 4 <property name="LOG_HOME" value="/log" />
 5 <!-- 控制台输出 -->
 6 <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
 7 <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
 8 <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
 9 <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
10 </encoder>
11 </appender>
12 <!-- 按照每天生成日志文件 -->
13 <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
14 <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
15 <!--日志文件输出的文件名-->
16 <FileNamePattern>${LOG_HOME}/TestWeb.log.%d{yyyy-MM-dd}.log</FileNamePattern>
17 <!--日志文件保留天数-->
18 <MaxHistory>30</MaxHistory>
19 </rollingPolicy>
20 <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
21 <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
22 <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
23 </encoder>
24 <!--日志文件最大的大小-->
25 <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
26 <MaxFileSize>10MB</MaxFileSize>
27 </triggeringPolicy>
28 </appender>
29 
30 <!-- 日志输出级别 -->
31 <root level="INFO">
32 <appender-ref ref="STDOUT" />
33 </root>
34 </configuration>

logback的配置文件,我直接从网上拷贝下来的,参考的网址是:http://www.cnblogs.com/warking/p/5710303.html。我的云桌面上的配置文件跟这个差不多,一行一行敲下来肯定不现实,所以直接从网上找了一个类似的。有些地方可以自己改一改,比如日志生成的路径啊,日志名字啊等等,还是很容易理解的。

OK,终于到最后了!是不是感觉这些框架配置起来挺麻烦的,一点错误都不能有,一旦xml中出错,查找起来还比较麻烦,因为没有报错机制啊,也不能设置断点一行一行查看,所有细心非常重要!接下来我们需要写一个测试类,用来测试上面所有的框架。简单点,就test.java:

 

test的目的是调用上面框架,代码也不少,一个一个敲实在是太麻烦,所以就贴图片了,格式会比较乱,但也没有办法。OK,到此,关于这个框架的搭建就差不多了。最后想说的是,后面的路还很长,我还是一个java初学者,需要努力加油!

 

日志

1.2017.9.11正式发布第一版本

 

以上是关于spring+mybatis+mina+logback框架搭建的主要内容,如果未能解决你的问题,请参考以下文章

Spring Cloud 最新版发布,干掉 JSch,支持 Mina,这次真的追不动了。。

Spring Cloud 最新版发布,干掉 JSch,支持 Mina,这次真的追不动了。。

Spring Cloud 最新版发布,干掉 JSch,支持 Mina,这次真的追不动了。。

Spring Cloud 最新版发布,干掉 JSch,支持 Mina,这次真的追不动了。。

JAVA通信系列二:mina入门总结

JAVA通信系列二:mina入门总结