2016/1/20 14:47:28


原创,转载请注明出处

曾经看过《那些年我们一起追过的女孩》,片中有个比较经典的画面,至今记忆犹新,柯景腾多年后,做了一名作家,每天面对电脑码字,背后是一张张一闪而过的字幅“人生就是不停的战斗”

作为程序员,我想一生就是不停的和BUG做战斗了,新来的这家公司,用的很老的Spring+Struts2.0+JDBC的框架,非常的不好用,其中的问题可以陈述10条以上,但是限于当时的技术水平所限,不能达到也很正常,所以我萌生了一个推翻重写后台的想法(从这到正文部分纯属装逼的,大神绕过,新人还是需要看一哈,熟悉一下为什么是MAVEN)

JAVA这门语言,之前看一个漫画是这么形容的,C++是加农炮,威力强大,什么都能炸;JAVA是一个手机,它能打电话叫来各种炮,炸的你爹妈不认得,但是它的JAR存在着依赖关系,比如Spring中的对AspectJ和JSR的支持是基于AspectJ和其他的JAR包的,你用它之前必须要先有依赖的jar包;项目中有两个典型的jar就是如此

  • aopalliance-1.0.jar 它是SpringAOP的基础依赖包
  • hamcrest-core-1.1.jar 他是Junit依赖的jar包

那么问题来了,我要是打电话,请人帮我“炸楼”,就好比JAVA请JAR包,我是不是连它爸妈一起请?我是不是要配置所有的依赖包,答案NO,因为我可以借助MAVEN这个神器啊,它会自动解析包的依赖关系去自动下载

在这个项目的搭建和第一次用maven没有人帮助我的情况下,能做出来还是有些小激动,也学习到了很多新的知识,重新把Spring学习了一遍,进一步理解了XML配置文件,SpringIOC和SpringAOP,惊叹于Spring框架的神奇之处,自己也掌握了许多Spring相关的技术,例如:Spring是支持JSON的,我们可以直接在控制层方法加@ResponseBody,可以自动返回JSON对象,So Easy

本文作者所用:所有东西的版本

  • MyEClipse GA 2014
  • Spring 4.2.4(最新)
  • Mybatis 3.3.0(最新)

参考博客

http://blog.csdn.net/zhshulin/article/details/37956105 http://blog.csdn.net/l349440843/article/details/45788017 http://blog.csdn.net/zhshulin/article/details/37937365

本文主要介绍的技术:(大神绕过)

  1. MAVEN搭建JAVA-WEB项目
  2. Spring的配置文件
  3. Junit单元测试
  4. Spring整合JSON输出
  5. Spring整合Mybatis不需要写DAO层代码
  6. Log4j控制输出,主要介绍扩展方式写日志进数据库的方式
  7. 代码注释的规范,和一些MyEclipse的规范操作(个人觉得规范的)

作为程序界的老鸟,看到这篇文章就自动过滤之前这一段,不过本作也真诚的希望你们能为我提出建议,谢谢,言归正传,开始操练

1.MAVEN

1.1首先搭建一个maven项目

第一次新建MAVEN项目的筒子,你们在这里要稍微等一哈,MAVEN要去下载依赖

WEB项目点中上面的maven-archetype-webapp点击下一步


Group Id一般填公司的包名吧,第二个填公司名,其实我也不是很懂这个= =好像没有多大用

然后MAVEN就开始在US镜像仓库下载包和一些准备工作了你的MyEclipse的右下角,就会出现

至此,你的MAVEN项目就初步搭建好了

1.2那么接下来怎么搞

搭建好的MAVEN项目如下图

问题有两个,一个我,作为一个高逼格的程序员,一定要用最新版本的JRE环境,所以把项目构建改到最高版本,另外,报了一个 “javax.servlet.http.HttpServlet” was not found on the Java Build Path index.jsp错误,这是由于在index.jsp页面上缺少对JavaEE的支持,因此需要添加JavaEE的类库

  1. 右键工程–>properties–>JAVA Build Path–>Edit
  2. 在pox.xml中添加对JAVA EE的依赖

1.3最后是pom.xml的配置

如果遇到环境配置的问题,可以参考博文:MyEclipse+Tomcat+MAVEN+SVN项目完整环境搭建

点开pom.xml配置你的项目maven依赖,坐等几分钟,maven会下载JAR,如果不下载,或者停止,就点开MyEclipse 找到 MAVEN4MyEclipse 把下载按钮打开,或者还原为默认的

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.zjx</groupId><artifactId>zjx</artifactId><packaging>war</packaging><version>0.0.1-SNAPSHOT</version><name>zjx Maven Webapp</name><url>http://maven.apache.org</url><properties>  <!-- spring版本号 -->  <spring.version>4.2.4.RELEASE</spring.version>  <!-- mybatis版本号 -->  <mybatis.version>3.3.0</mybatis.version>  <!-- log4j日志文件管理包版本 -->  <slf4j.version>1.7.7</slf4j.version><log4j.version>1.2.16</log4j.version>   </properties><dependencies><!-- 单元测试的依赖 --> <dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.10</version><scope>test</scope></dependency>   <!-- spring核心包 -->  <dependency>  <groupId>org.springframework</groupId>  <artifactId>spring-core</artifactId>  <version>${spring.version}</version>  </dependency> <!-- spring对web的支持 -->  <dependency>  <groupId>org.springframework</groupId>  <artifactId>spring-web</artifactId>  <version>${spring.version}</version>  </dependency> <!-- spring对ORM映射的支持-->   <dependency>  <groupId>org.springframework</groupId>  <artifactId>spring-oxm</artifactId>  <version>${spring.version}</version>  </dependency> <!-- spring事务管理支持 -->   <dependency>  <groupId>org.springframework</groupId>  <artifactId>spring-tx</artifactId>  <version>${spring.version}</version>  </dependency>  <!-- spring对JDBC的支持 -->  <dependency>  <groupId>org.springframework</groupId>  <artifactId>spring-jdbc</artifactId>  <version>${spring.version}</version>  </dependency>  <!-- spring对MVC框架的支持 -->  <dependency>  <groupId>org.springframework</groupId>  <artifactId>spring-webmvc</artifactId>  <version>${spring.version}</version>  </dependency>  <!-- spring切面支持 -->  <dependency>  <groupId>org.springframework</groupId>  <artifactId>spring-aop</artifactId>  <version>${spring.version}</version>  </dependency>  <!-- spring上下文支持 -->  <dependency>  <groupId>org.springframework</groupId>  <artifactId>spring-context-support</artifactId>  <version>${spring.version}</version>  </dependency>  <!-- spring测试支持 -->  <dependency>  <groupId>org.springframework</groupId>  <artifactId>spring-test</artifactId>  <version>${spring.version}</version>  </dependency> <!-- AspectJ支持 --><dependency><groupId>aspectj</groupId><artifactId>aspectjrt</artifactId><version>1.5.4</version></dependency> <!-- 织入 --><dependency><groupId>aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.5.4</version></dependency><!-- mybatis核心包 -->  <dependency>  <groupId>org.mybatis</groupId>  <artifactId>mybatis</artifactId>  <version>${mybatis.version}</version>  </dependency>  <!-- mybatis对spring的支持 -->  <dependency>  <groupId>org.mybatis</groupId>  <artifactId>mybatis-spring</artifactId>  <version>1.2.3</version>  </dependency>  <!-- 导入Mysql数据库链接jar包 -->  <dependency>  <groupId>mysql</groupId>  <artifactId>mysql-connector-java</artifactId>  <version>5.1.30</version>  </dependency> <!-- 导入dbcp的jar包,用来在applicationContext.xml中配置数据库 -->  <dependency><groupId>commons-dbcp</groupId><artifactId>commons-dbcp</artifactId><version>1.4</version></dependency><!-- JSTL标签类 -->  <dependency>  <groupId>jstl</groupId>  <artifactId>jstl</artifactId>  <version>1.2</version>  </dependency>  <!-- 日志文件管理包 --> <!-- log start --> <dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version></dependency> <dependency>  <groupId>log4j</groupId>  <artifactId>log4j</artifactId>  <version>${log4j.version}</version>  </dependency> <!-- 格式化对象,方便输出日志 -->  <dependency>  <groupId>com.alibaba</groupId>  <artifactId>fastjson</artifactId>  <version>1.1.41</version>  </dependency> <!-- 导入java ee jar 包 -->  <dependency>  <groupId>javax</groupId>  <artifactId>javaee-api</artifactId>  <version>7.0</version>  </dependency>  <dependency>  <groupId>org.slf4j</groupId>  <artifactId>slf4j-api</artifactId>  <version>${slf4j.version}</version>  </dependency>  <dependency>  <groupId>org.slf4j</groupId>  <artifactId>slf4j-log4j12</artifactId>  <version>${slf4j.version}</version>  </dependency>  <!-- log end --><!-- 映入JSON支持 --> <dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId><version>2.5.1</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.5.1</version></dependency> <dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.5.1</version></dependency><!-- 文件上传 --><dependency>  <groupId>commons-fileupload</groupId>  <artifactId>commons-fileupload</artifactId>  <version>1.3.1</version>  </dependency>  <dependency>  <groupId>commons-io</groupId>  <artifactId>commons-io</artifactId>  <version>2.4</version>  </dependency>  <dependency>  <groupId>commons-codec</groupId>  <artifactId>commons-codec</artifactId>  <version>1.9</version>  </dependency>  </dependencies><build><finalName>zjx</finalName></build></project>

所有的依赖包,和作用都注释清楚,至此,MAVEN的工作就完了,剩下的事情就是项目

2. Spring配置文件

首先,先几个题外话,所有人都知道程序分离是为了简化,人们习惯上把复杂的事情分解为若干个简单的事情处理,这就体现的是分层思想,所以程序上才有了MVC,才有了三层架构

当人们认知事物的高度达到一定程度之后,就会抓住事物的核心问题,也就是程序设计上常说的问题域,那么请看下面两个故事:

让时间回到2001年,地点是澳大利亚悉尼的Clarence Street有一家叫做Cirrus Technologies的公司,这是一家做J2EE企业级应用开发和咨询的公司,在会议桌上一个小伙子和老板正在进行着激烈的讨论。
小伙子:”老板,我总觉得开发的效率太低了,我用了EJB的Entity bean 1.1时,我总觉得我浪费了好多时间在处理Entity Bean的体系架构上,却没有花时间在核心业务逻辑的开发上,而且CMP给我们的限制太多了”。
老板:”Gavin,别傻了,EJB是业界的标准,也是最流行的技术,而且我们公司是IBM的合作伙伴。如果有问题,问题就是我们还没有适应这样的开发模式”。
小伙子:”不,我觉得肯定有更好的解决的方案。我们可以设计出比Entity Bean更好的方案”。
老板:”哦,Gavin,我知道你很聪明,开发水平也不错。但是开发这样的系统太难了,而且你根本就没有用SQL开发过任何数据库系统。不要想这样一个不现实的目标啦!”
小伙子皱了皱眉,说道:”不,我相信我有能力开发出这个系统。我的想法绝对是可行的。”
(注:以上场景纯属虚构,但至少以下内容完全属实:Gavin King开发hibernate的动机有两个:发现CMP太烂;赢得对老板的争执。Gavin King当时没有任何用SQL开发数据库的经验,Gavin King开发hibernate的第一件事是去街上买了本SQL基础的书)

也许Cirrus Technologies的老板做梦也想不到两年以后,这个小伙子开发出的那个产品会成为全世界最流行的O/R Mapping工具,而那个对SQL和数据库一窍不通的小伙子居然会成为全世界J2EE数据库解决方案的领导者。

这就是Gavin King,一个充满激情、脾气很倔、永不言败的人。他的成就也许全世界搞Java的人都知道:他是hibernate的创始人;他是EJB 3.0的Entity bean specification的实际领导人(sun任命的领导人应该是Linda DeMichiel);他也是那本经典的书hibernate in action的作者;他也参加了XDoclet和Middlegen的开发;他在全世界各种著名的会议(TheServerSide Symposium等)进行演讲和讲座。

2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。它的广告语是“我们已经学习了SQL,为什么我们还要学习HQL”;

故事给我的感触是,必须要学习新的技术,永远做第一个吃螃蟹的人,因为只有你知道了什么框架,有什么不足,你才会去改进,才会去发明新的框架,这也就是许多大牛,喜欢钻研技术,自己写框架,而不用别人现成的框架,小弟只是个渣渣,各位路过的大神勿喷,能指点我一二最好

不扯闲话:上配置(配置也体现了控制层和业务层分离的思想),因为项目开发的主要问题域在于业务逻辑的处理上,而不在DAO代码上,因此没有写DAO层,而交给Mybatis去自动控制,也体现了故事一种的思想,配置文档截图如下

  • applicationContext-action.xml 是专门配置持久层的
  • applicationContext-base.xml 是专门配置控制层的
  • jdbc.properties 是专门配置数据库连接的,这样配置提现分离和修改数据库的作用
  • log4j.properties 是专门配置日志输出和日志控制的
  • mybatis.cfg.xml 是为了提供ORM映射的配置,其中只需要配置一个类的别名,mapper已经移交Spring管理,但是个人嫌写类名麻烦,喜欢用别名
  • mybatis.cfg.xml 这个配置可以不要,看到有大神才用注解的方式,希望有大神路过不吝赐教

applicationContext-action.xml

<?xml version="1.0" encoding="UTF-8"?><beans  xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"> <!-- 自动扫描该包,使SpringMVC认为包下用了@controller注解的类是控制器,控制器全部放在这个包下 -->  <context:component-scan base-package="com.zjx.action">
<!--  如果使用包含采用该配置       <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> -->
<!--  如果使用过滤采用该配置   <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/> --></context:component-scan><!--避免IE执行AJAX时,返回JSON出现下载文件 -->  <bean id="mappingJacksonHttpMessageConverter"  class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">  <property name="supportedMediaTypes">  <list>  <!-- 设置返回的编码和解析方式 --><value>text/html;charset=UTF-8</value>  </list>  </property>  </bean>  <!-- 启动SpringMVC的注解功能,完成请求和注解POJO的映射 -->  <bean  class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">  <property name="messageConverters">  <list>  <ref bean="mappingJacksonHttpMessageConverter" /> <!-- JSON转换器 -->  </list>  </property>  </bean>  <!-- 定义跳转的文件的前后缀 ,视图模式配置-->  <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">  <!-- 这里的配置我的理解是自动给后面action的方法return的字符串加上前缀和后缀,变成一个 可用的url地址 -->  <property name="prefix" value="/WEB-INF/jsp/" />  <property name="suffix" value=".jsp" />  </bean>  <!-- 配置文件上传,如果没有使用文件上传可以不用配置,当然如果不配,那么配置文件中也不必引入上传组件包 -->  <bean id="multipartResolver"    class="org.springframework.web.multipart.commons.CommonsMultipartResolver">    <!-- 默认编码 -->  <property name="defaultEncoding" value="utf-8" />    <!-- 文件大小最大值 -->  <property name="maxUploadSize" value="10485760000" />    <!-- 内存中的最大值 -->  <property name="maxInMemorySize" value="40960" />    </bean>   </beans>

applicationContext-base.xml

<?xml version="1.0" encoding="UTF-8"?><beans  xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"> <aop:aspectj-autoproxy></aop:aspectj-autoproxy><!-- 自动扫描 -->  <context:component-scan base-package="com.zjx" />  <!-- 引入配置文件 -->  <bean id="propertyConfigurer"  class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">  <property name="location" value="classpath:jdbc.properties" />  </bean> <!-- 配置数据源 --><bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">  <property name="driverClassName" value="${jdbc.driver}" />  <property name="url" value="${jdbc.url}" />  <property name="username" value="${jdbc.username}" />  <property name="password" value="${jdbc.password}" />  <!-- 初始化连接大小 -->  <property name="initialSize" value="${jdbc.initialSize}"></property>  <!-- 连接池最大数量 -->  <property name="maxActive" value="${jdbc.maxActive}"></property>  <!-- 连接池最大空闲 -->  <property name="maxIdle" value="${jdbc.maxIdle}"></property>  <!-- 连接池最小空闲 -->  <property name="minIdle" value="${jdbc.minIdle}"></property>  <!-- 获取连接最大等待时间 -->  <property name="maxWait" value="${jdbc.maxWait}"></property>  </bean>  <!-- spring和MyBatis整合-->  <bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">  <property name="dataSource" ref="dataSource" />  <!-- 指明mybatis主配置文件路径 --><property name="configLocation" value="classpath:mybatis.cfg.xml"></property><!-- 指明mybatis的映射位置 --><property name="mapperLocations"><list><value>classpath:orm/*.xml</value></list></property></bean><!-- 配置SqlSession模版类,SqlSessionTemplate是线程安全类 --><bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate" scope="prototype"><constructor-arg  ref="sessionFactory"></constructor-arg>       </bean><!-- 事务管理器 --><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"></property></bean><!-- 允许使用注解配置事务 --><tx:annotation-driven transaction-manager="transactionManager"/> <!-- 扫描spring注解类 --><context:component-scan base-package="com.zjx"><context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/><context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/></context:component-scan></beans>

jdbc.properties

jdbc.driver=org.gjt.mm.mysql.Driver
#定义连接的URL地址,设置编码集,允许多条SQL语句操作
jdbc.url=jdbc:mysql://localhost:3306/test?characterEncoding=utf-8&amp;allowMultiQueries=true
jdbc.username=root
jdbc.password=82651205
#定义初始连接数
jdbc.initialSize=10
#定义最大连接数
jdbc.maxActive=20
#定义最大空闲
jdbc.maxIdle=20
#定义最小空闲
jdbc.minIdle=10
#定义最长等待时间
jdbc.maxWait=60000

log4j.properties

### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n### direct messages to file hibernate.log ###
#log4j.appender.file=org.apache.log4j.FileAppender
#log4j.appender.file.File=hibernate.log
#log4j.appender.file.layout=org.apache.log4j.PatternLayout
#log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n### set log levels - for more verbose logging change 'info' to 'debug' ###log4j.rootLogger=warn, stdout#log4j.logger.org.hibernate=info
#log4j.logger.org.hibernate=debug### log HQL query parser activity
#log4j.logger.org.hibernate.hql.ast.AST=debug### log just the SQL
#log4j.logger.org.hibernate.SQL=debug### log JDBC bind parameters ###
#log4j.logger.org.hibernate.type=info
#log4j.logger.org.hibernate.type=debug### log schema export/update ###
#log4j.logger.org.hibernate.tool.hbm2ddl=debug### log HQL parse trees
#log4j.logger.org.hibernate.hql=debug### log cache activity ###
#log4j.logger.org.hibernate.cache=debug### log transaction activity
#log4j.logger.org.hibernate.transaction=debug### log JDBC resource acquisition
#log4j.logger.org.hibernate.jdbc=debug### enable the following line if you want to track down connection ###
### leakages when using DriverManagerConnectionProvider ###
#log4j.logger.org.hibernate.connection.DriverManagerConnectionProvider=trace################################################################################
########文件记录日志的方式##定义LOG输出级别
#log4j.rootLogger=INFO,Console,File
##定义日志输出目的地为控制台
#log4j.appender.Console=org.apache.log4j.ConsoleAppender
#log4j.appender.Console.Target=System.out
##可以灵活地指定日志输出格式,下面一行是指定具体的格式
#log4j.appender.Console.layout = org.apache.log4j.PatternLayout
#log4j.appender.Console.layout.ConversionPattern=[%c] - %m%n
#
##文件大小到达指定尺寸的时候产生一个新的文件
#log4j.appender.File = org.apache.log4j.RollingFileAppender
##指定输出目录
#log4j.appender.File.File = logs/ssm.log
##定义文件最大大小
#log4j.appender.File.MaxFileSize = 10MB
## 输出所以日志,如果换成DEBUG表示输出DEBUG以上级别日志
#log4j.appender.File.Threshold = ALL
#log4j.appender.File.layout = org.apache.log4j.PatternLayout
#log4j.appender.File.layout.ConversionPattern =[%p] [%d{yyyy-MM-dd HH:mm:ss}][%c]%m%n################################################################################
########数据库记录日志的方式
log4j.logger.com.zjx.util=error,database
log4j.appender.database=org.apache.log4j.jdbc.JDBCAppender
log4j.appender.database.URL=jdbc:mysql://localhost:3306/test?characterEncoding=utf-8
log4j.appender.database.driver=org.gjt.mm.mysql.Driver
log4j.appender.database.user=root
log4j.appender.database.password=82651205
log4j.appender.database.sql=INSERT INTO t_log(content,logDate) VALUES ('%m','%d{yyyy-MM-dd}')
log4j.appender.database.layout=org.apache.log4j.PatternLayout
log4j.appender.database.layout.ConversionPattern=%m

mybatis.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration  PUBLIC   "-//mybatis.org//DTD Config 3.0//EN"  "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>    <typeAliases><!-- 如果还有其余的映射类,则继续添加 --><typeAlias type="com.zjx.bean.UserBean" alias="user"/></typeAliases></configuration>

UserBean.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="user"><!-- 结果集映射 --><resultMap type="user" id="userMap"><result property="passWord" column="pwd"/></resultMap><select id="findById" parameterType="int" resultMap="userMap">select * from t_user where id = #{id};</select><!-- 字段模糊的动态语句 --><sql id="paramSql"><if test="userName !=null and userName != ''">and userName like '%${userName}%' </if></sql><select id="findPage" resultMap="userMap">select * from t_userwhere 1=1 <include refid="paramSql"></include> limit #{start},#{pageSize}</select><select id="findCount" resultType="int">select count(*) from t_user where 1=1 <include refid="paramSql"></include></select></mapper>

3.Junit测试

表自己建好,我也懒

那么首先书写实体:

package com.zjx.bean;import java.sql.Date;/** * @Description 用户实体类* @author tony_kanper* @date 2016年1月20日 上午11:30:32 * @version V1.0 * */
public class UserBean {/*** id*/private int id;/*** 用户名*/private String userName;/*** 生日*/private Date birthday;/*** 密码*/private String passWord;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public Date getBirthday() {return birthday;}public void setBirthday(Date birthday) {this.birthday = birthday;}public String getPassWord() {return passWord;}public void setPassWord(String passWord) {this.passWord = passWord;}@Overridepublic String toString() {return "UserBean [id=" + id + ", userName=" + userName + ", birthday="+ birthday + ", passWord=" + passWord + "]";}public UserBean(String userName, Date birthday, String passWord) {super();this.userName = userName;this.birthday = birthday;this.passWord = passWord;}public UserBean() {super();}}

业务接口Service

package com.zjx.service;import com.zjx.bean.CutPageBean;
import com.zjx.bean.UserBean;/** * @Description: 用户业务接口* @author tony_kanper* @date 2016年1月20日 上午11:30:50 * @version V1.0 * */
public interface IUserService {/*** 每页显示记录数*/public final int PAGESIZE = 10;/*** @Desciption 按照用户id查找该用户* @param id 用户id* @return 用户实体*/public UserBean findById(int id);/*** @Description 按照页码和用户姓名模糊字查找用户分页对象* @param pageNO 页码* @param userName 用户姓名模糊字* @return 分页对象*/public CutPageBean<UserBean> findByItem(int pageNO,String userName);
}

业务接口实现类ServiceImpl超类和具体实现类

package com.zjx.service.impl;import java.util.HashMap;
import java.util.List;
import java.util.Map;import javax.annotation.Resource;import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.stereotype.Service;import com.zjx.bean.CutPageBean;
/** * @Description 所有业务实现类的超类* @author tony_kanper* @date 2016年1月20日 上午11:31:07 * @version V1.0 ** @param <T> 通用泛型*/
@Service
public class BaseService<T> {/*** SqlSesion模板类*/@Resourceprotected SqlSessionTemplate session;/*** @Description 所有的查询分页对象的超类方法* @param pageNO 页码* @param pageSize 每页显示记录数* @param paramMap 需要查询的字段集合* @param listSql 查询某页记录的SQL语句* @param countSql 查询总记录数的SQL语句* @return 分页对象*/public CutPageBean<T> cutpage(int pageNO, int pageSize,Map<String, Object> paramMap, String listSql, String countSql) {CutPageBean<T> cutBean = new CutPageBean<T>();if (paramMap == null) {paramMap = new HashMap<String, Object>();}// 设置查询的起始页paramMap.put("start", (pageNO - 1) * pageSize);// 设置查询页开始向后的记录数paramMap.put("pageSize", pageSize);// 查询Mybatis配置文件下,命名空间内的查询结果List<T> list = this.session.selectList(listSql, paramMap);cutBean.setList(list);// 设置总记录数int count = this.session.selectOne(countSql, paramMap);cutBean.setCount(count);// 设置总页数cutBean.setTotalPage(count / pageSize);if (count % pageSize != 0) {cutBean.setTotalPage(count / pageSize + 1);}return cutBean;}}

具体实现类如下

package com.zjx.service.impl;import java.util.HashMap;
import java.util.Map;import org.springframework.stereotype.Service;import com.zjx.bean.CutPageBean;
import com.zjx.bean.UserBean;
import com.zjx.service.IUserService;
/** * @Description 用户业务实现类 * @author tony_kanper* @date 2016年1月20日 上午11:50:57 * @version V1.0 * */
@Service
public class UserServiceImpl extends BaseService<UserBean> implements IUserService {@Overridepublic UserBean findById(int id) {// 测试切面类是否完成错误记录进入数据库时,解除注释// throw new NullPointerException();return session.selectOne("user.findById", id);}@Overridepublic CutPageBean<UserBean> findByItem(int pageNO, String userName) {Map<String, Object> paramMap = new HashMap<>();paramMap.put("userName", userName);return cutpage(pageNO, PAGESIZE, paramMap, "user.findPage", "user.findCount");}}

测试类:

测试类超类:

package com.zjx.test;import org.junit.After;
import org.junit.Before;
import org.springframework.beans.BeansException;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.util.StringUtils;public class UnitTestBase {/*** 相对路径应用上下文*/private ClassPathXmlApplicationContext context;/*** XML文件的存放路径*/private String springXmlPath;public UnitTestBase() {}public UnitTestBase(String springXmlPath){this.springXmlPath = springXmlPath;}/*** 加载XML文件*/@Beforepublic void before(){if (StringUtils.isEmpty(springXmlPath)) {springXmlPath = "classpath*:spring-*.xml";}try {// 多个xml文件用逗号或者空格符隔开,均可加载context = new ClassPathXmlApplicationContext(springXmlPath.split("[,\\s]+"));context.start();} catch (BeansException e) {e.printStackTrace();}}/*** 销毁*/@Afterpublic void after(){context.destroy();}/*** @param beanId SpringXML文件中的bean的id* @return 该bean的id对应下的实例,默认单例*/@SuppressWarnings("unchecked")protected <T extends Object> T getBean(String beanId){try {return(T)context.getBean(beanId);} catch (BeansException e) {e.printStackTrace();return null;}}/*** @param clazz 通过类模板获取该类* @return 该类的实例,默认单例*/protected <T extends Object> T getBean(Class<T> clazz){try {return context.getBean(clazz);} catch (BeansException e) {e.printStackTrace();return null;}}
}

测试类

package com.zjx.test;import org.junit.runner.RunWith;
import org.junit.runners.BlockJUnit4ClassRunner;import com.zjx.service.IUserService;@RunWith(BlockJUnit4ClassRunner.class)
public class Test extends UnitTestBase{public Test() {super("classpath:applicationContext-base.xml");}@org.junit.Testpublic void testUnit(){ IUserService service = super.getBean("userServiceImpl");System.out.println(service.findByItem(1, "张"));}}

这样测试,免去了注释实现类中的测试类的麻烦,并且在pom.xml中设置了scope它仅在测试时引入这个包,实际使用时,并不会用到

<!-- 单元测试的依赖 -->
<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.10</version><scope>test</scope>
</dependency>

4.Spring整合JSON输出

也许小伙伴会问,不是说好了,要来玩JSON吗?

<!--避免IE执行AJAX时,返回JSON出现下载文件 -->
<bean id="mappingJacksonHttpMessageConverter"  class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">  <property name="supportedMediaTypes">  <list>  <!-- 设置返回的编码和解析方式 --><value>text/html;charset=UTF-8</value>  </list>  </property>
</bean>
<!-- 启动SpringMVC的注解功能,完成请求和注解POJO的映射 -->
<bean  class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">  <property name="messageConverters">  <list>  <ref bean="mappingJacksonHttpMessageConverter" /> <!-- JSON转换器 -->  </list>  </property>
</bean>

Spring对JSON的支持也挺恶心的,如果Spring的版本足够高,他对JSON的支持会用到配置文件中的MappingJackson2HttpMessageConverter,注意这个Jackson2,如果你按着ctrl没链接,那么把2删除,说明你用的Spring版本是之前的,你用的json版本1也都足够了,如果你只能用2,那么,你的pom.xml中必须加入2.0版本以上的依赖,对此Spring上的说明也是这样的,楼主看了很久的源码= =,快给我点赞

<!-- 映入JSON2.5支持 --> <dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId><version>2.5.1</version>
</dependency>
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.5.1</version>
</dependency>
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.5.1</version>
</dependency>

由图可知,在类的注释上最后一行,说明MappingJackson2HttpMessageConverter兼容Jackson 2.1和更高版本,之所以贴出来说,是想说明看源码很重要,也想说明我不是乱说的

接下来写一个JSP页面发送AJAX请求试试

<%@ page language="java" pageEncoding="UTF-8"%>
<html>
<body>
<h2>Hello World!</h2>
<hr/>
<a href="/zjx/user/nextPage.do">去看看用户页</a>
<script type="text/javascript" src="/zjx/jquery-2.1.4.min.js"></script>
<script type="text/javascript">$(function(){$.post("/zjx/user/findById.do","id=1",function(data){alert(data);});});</script>
</body>
</html>

action控制层:

package com.zjx.action;import javax.annotation.Resource;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;import com.zjx.bean.CutPageBean;
import com.zjx.bean.UserBean;
import com.zjx.service.IUserService;/** * @Description 用户控制器* @author tony_kanper* @date 2016年1月20日 上午11:33:46 * @version V1.0 * */
@Controller
@RequestMapping("/user")
public class UserAction {/*** 注入的业务接口*/@Resourceprivate IUserService service;/*** @Description 根据视图层传入的id调用业务方法查找到用户后采用转换为JSON对象返回* @param id 用户id* @return 用户实体的JSON对象*/@RequestMapping("/findById")@ResponseBody//Spring集成的JSON,可以将Model转换为JSON对象存放在HttpServletResponse中private UserBean findById(int id){return service.findById(id);    }/*** @Description 按照页码和姓名模糊字查找某页全部用户对象* @param pageNO 页码* @param userName 用户姓名模糊字* @return 某页全部用户对象(JSON)*/@RequestMapping("/findByPageAndName")@ResponseBodyprivate CutPageBean<UserBean> findByPageAndName(int pageNO,String userName){return service.findByItem(pageNO, userName);} /*** @Description 测试是否跳转去WEB-INF目录下的jsp页面* @return 返回视图的名称*/@RequestMapping("/nextPage")private String nextPage(){return "allUserPage";}
}

嘿,通过测试,还真的在页面拿到了JSON数据呢,好神奇啊

5.Spring整合Mybatis不需要写DAO层代码

话说,倪们看到我写了DAO层代码了吗?因为DAO已经写到UserBean.xml中和配置里了,要是不懂这个XML里面怎么写SQL语句,就网上或者买书看看,不多说;

这里值得一提的是,我用了SqlSessionTemplate这个类,这个类有点搞笑,他是自动管理的,也就是说,他的创建销毁是不必依赖Spring的,也就是说,当SQL模版类查询结束之后,他自己就知道关闭了,而懂点SpringIOC的筒子都知道,bean默认是单例的,那么要是他自己关了,或者别人又用了这个类,并发的访问扎个办?答案是:你知道Mybatis的工程师有多骚不?

这个SqlSessionTemplate的注释是这个意思,他是线程安全的,是受Spring管理的,和Spring事务管理器一起工作保证只用在一个当前的线程,它也是Spring管理下的事务内;此外,它管理会话的生命周期,包括关闭,提交或回滚基于Spring事务配置必要的

看到这里,也就是说,Mybatis的工程师们,把这个棘手的问题甩给Spring去管,他们就当甩手掌柜了啊,反正有mybatis-spring.jar这个提供对Spring支持的神器在

<!-- mybatis对spring的支持 -->
<dependency>  <groupId>org.mybatis</groupId>  <artifactId>mybatis-spring</artifactId>  <version>1.2.3</version>
</dependency>

也正是如此,我们在配置base的时候,会将模版类设置为多例,我问骚年你为何如此勇敢,因为它是线程安全的,也受Spring的管理

<!-- 配置SqlSession模版类,SqlSessionTemplate是线程安全类 -->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate" scope="prototype"><constructor-arg  ref="sessionFactory"></constructor-arg>
</bean>

另外,就算你不写这个多例,也不影响,最多报个警告

WARN DisposableBeanAdapter:364 - Invocation of destroy method ‘close’ failed on bean with name ‘sqlSession’: java.lang.UnsupportedOperationException: Manual close is not allowed over a Spring managed SqlSession

这个警告是说,在Spring管理下的sqlSession是不允许自己关闭的

PS:如果有大神找到其中更深的缘由,请不吝赐教

6. Log4j控制输出

关于Log4j的东西,网上太多了,各位慢慢看,个人觉得这篇博文蛮不错

Log4j配置详解

关于扩展输出的,我用的是AOP方式

工具类如下:

package com.zjx.util;import java.sql.Date;
import java.text.SimpleDateFormat;import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Service;/** * @Description 日志处理类* @author tony_kanper* @date 2016年1月20日 上午11:39:48 * @version V1.0 * */
@Service
@Aspect
public class LogRecord {/*** 日期格式化输出对象*/private SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss");/*** 日志对象*/private Logger log = Logger.getLogger(LogRecord.class);/*** @Description 在方法抛出异常之后,记录异常信息,并将异常信息以error等级封装到log对象中* @param point 切入点* @param e 方法抛出的异常*/@AfterThrowing(value = "execution(* com.zjx.service.impl.*.*(..))", throwing = "e")public void writeLog(JoinPoint point, Exception e) {// 得到目标对象的类名String className = point.getTarget().getClass().getName();// 得到目标对象的方法名String methodName = point.getSignature().getName();// 当前日期String timeStr = df.format(new Date(System.currentTimeMillis()));// 得到异常类信息String exceptionStr = e.getClass().getName();String info = timeStr+" 在"+className+"的 "+methodName+"()方法,抛出"+exceptionStr+"异常";//System.out.println(info);log.error(info);}
}

一旦在com.zjx.service.impl包下的所有类的所有方法抛出异常之后,都会向log日志对象写入错误信息,并且在log4j配置文档中写入数据库,经测试无误

PS:对于环绕通知,和其它通知方式,关于订单类的记录,有大神会的,希望给我一个DEMO谢谢

附上邮箱:tony_kanper@hotmail.com

7.代码注释的规范

之前的项目也不是无可挽救,但是代码实在是太糟糕了,没用注释,或者关键性的注释用单行注释而不用文档注释,这对于代码阅读是相当困难的

对于文档注释,可以生成Javadoc,同时,当鼠标浮动到具有文档注释的类/方法/变量时,能提供说明,简单粗暴

通常我们可以在Myeclipse中配置你的注释样本

如图,我的文件注释上,拥有标题,包,文件描述,作者创建日期等信息

当然,你也可以通过Edit编辑你的输出样式

然后你可以按住Alt+Shirft+J快速在相应位置生成注释

最后你只需要填就是了

程序员一定要养成写注释的习惯,不关多大的公司,就说国内的支付宝,别个写对外接口不也一样写好的文档注释和代码的单行注释,我等菜鸟,更应该如此,这更多的是为了今后的程序员便于维护,而不是为了你看懂(当然你肯定希望别人写好注释)

8.最后

花了很多时间学习这些,最后的收获也蛮大,希望能遇到更多志同道合的朋友

项目中容易遇到的问题主要有这些,有的问题之前我已经提到了

  1. MAVEN环境变量的配置,在path中加入%MAVEN_HOME%\bin;如果还需要配置jar包的仓库可以参看博文MyEclipse+Tomcat+MAVEN+SVN项目完整环境搭建
  2. 对于SqlSession报错的问题,要加多例
  3. 对于Spring配置文件读取jdbc.properties文件时,报错,有可能是mySQL的权限验证问题,它会默认使用系统的userName,解决方案有两种,一种参看博文mysql启动问题access denied for user ‘root’@’localhost’(using password:YES) 另一种是找到mysql安装目录,在my.ini中,以记事本打开的文末添加–skip-grant-tables
  4. 对于Spring版本较低的,Json,可以用如下依赖

    org.codehaus.jackson
    jackson-mapper-asl
    1.9.13

  5. MAVEN仓库传送门MAVEN仓库,你只需要像百度一样在搜索栏中输入jar,它们自动会为你找到最新版本jar包依赖

  6. Myeclipse GA 2014的下载门,做为程序员肯定要用最新版的哇,遇到问题去解决就是了,不要怕遇到问题而用旧版,很多过时方法和不支持的东西,新的东西,永远更多插件支持,永远兼容旧版http://www.my-eclipse.cn/
  7. 如果有兴趣,可以关注我的CSDN http://blog.csdn.net/kang82651204/

本文源码: http://download.csdn.net/detail/kang82651204/9412243

MAVEN整合Spring+SpringMVC+Mybatis相关推荐

  1. SSM整合——Spring+SpringMVC+MyBatis整合

    文章目录 1. 数据库环境 2. 项目基本结构搭建 3. 配置MyBatis 4. 配置Spring 5. 配置SpringMVC 6. Controller和视图层编写 7. 配置Tomcat,进行 ...

  2. intelliJ idea 使用maven创建spring+springMVC+mybatis(SSM)

    2019独角兽企业重金招聘Python工程师标准>>> ssm demo github : [https://github.com/rongyaya1003/ssmDemo.git] ...

  3. SSM框架整合(IntelliJ IDEA + maven + Spring + SpringMVC + MyBatis)

    使用IDEA创建Spring + SpringMVC + MyBatis 框架的Maven的项目. 一. 创建maven项目 1. File -> New Module,进入创建项目窗口. 2. ...

  4. Maven整合SSM框架(maven+spring+springmvc+mybatis)

    啊哈,终于到了用Maven整合SSM这个扑街含家产了.弄了整整一天才跑通.Mybatis的配置有些繁琐,跟之前学习的那个有点出去,加上Eclipse的Spring工具没有弄,配置的时候没有提示被搞蒙圈 ...

  5. Spring+SpringMVC+MyBatis+Maven框架整合

    本文记录了Spring+SpringMVC+MyBatis+Maven框架整合的记录,主要记录以下几点  一.Maven需要引入的jar包  二.Spring与SpringMVC的配置分离  三.Sp ...

  6. Spring+SpringMVC+MyBatis+easyUI整合基础篇(一)项目简述及技术选型介绍

    作者:13 GitHub:https://github.com/ZHENFENG13 版权声明:本文为原创文章,未经允许不得转载. 萌芽阶段 很久之前就开始打算整理一下自己的技术博客了,由于各种原因( ...

  7. Spring+SpringMVC+MyBatis整合基础篇

    基础篇 Spring+SpringMVC+MyBatis+easyUI整合基础篇(一)项目简介 Spring+SpringMVC+MyBatis+easyUI整合基础篇(二)牛刀小试 Spring+S ...

  8. SSM三大框架整合(Spring+SpringMVC+MyBatis)

    文章目录 SSM整合 一.导入依赖 1.1 Spring依赖 1.2 SpringMVC依赖 1.3 MyBatis依赖 二.配置文件 2.0 Web.xml 配置文件 2.1 Spring的配置文件 ...

  9. SSM框架详细整合教程(Spring+SpringMVC+MyBatis)

    动机 使用maven已经有一段时间了,但项目是别人搭建好的,因此一直想着自己要学习搭建一下.网上找了些资料后,结合自己实验,花了点时间就搞好,老样子,写在博客上,免得日后忘记. 本文链接:http:/ ...

最新文章

  1. Redis配置到本地以及可视化工具的安装运用
  2. 大数据-spark-hbase-hive等学习视频资料
  3. 见鬼,结果还就这样了
  4. WAT中Security选项卡无法连接到数据库解决办法
  5. [LeetCode]k个一组翻转链表(Reverse Nodes in k-Group)
  6. VTK:金字塔用法实战
  7. 自学python考哪些证书-学Python能挣多少钱?哪些人适合学Python?
  8. PHP ERROR : Call to undefined function curl_init()
  9. Bnuoj-29359 Deal with numbers 线段树
  10. 第二章 人工智能专题之Python进阶 - Matplotlib库
  11. 计算机组成原理(2021最新版)面试知识点集锦
  12. win10鼎信诺为什么安装不了_两个方法教你彻底解决win10系统更新补丁安装失败的问题-系统操作与应用 -亦是美网络...
  13. bcnf分解算法_BCNF范式及其分解方法(对一次Lab作业的总结)
  14. 快速掌握maya软件(基础建模)
  15. Windows系统蓝屏机制
  16. ftp上传软件,五款ftp优秀的ftp上传软件
  17. 设正整数n的十进制表示为n=ak……a1a0(0=ai=9,0=i=k,ak!=0),n的个位为起始数字的数字的正负交错之和T(n)=a0+a1+……+(-1)kak,证明:11|n的充分必要...
  18. python数据分析设置教程视频_炼数成金女讲师Python数据分析实战应用视频教程
  19. 如何在本地搭建FTP服务器以及搭建后的用途
  20. Java计算圆、长方形、正方形的面积及周长,并比较打印各个图形的大小

热门文章

  1. 管理员模式 运行msi_如何强制使用管理员模式安装MSI软件包
  2. gazebo又卡又慢?快把你的显卡用起来!点击查看如何使用显卡运行gazebo~
  3. Day21、22防火墙
  4. JumpServer安装
  5. LocalDate方法使用总结
  6. box2d系列之 反作用力的实现
  7. 【Verilog-19.3】define和undef的用法
  8. 动态规划时间规整简介入门
  9. 通过 域控服务器 访问客户端“计算机管理”
  10. tomcat端口介绍以及配置启用https