您的位置:首页 > 编程语言 > Java开发

MAVEN整合Spring+SpringMVC+Mybatis

2016-01-20 18:07 946 查看

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

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

MAVEN搭建JAVA-WEB项目

Spring的配置文件

Junit单元测试

Spring整合JSON输出

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

Log4j控制输出,主要介绍扩展方式写日志进数据库的方式

代码注释的规范,和一些MyEclipse的规范操作(个人觉得规范的)

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

1.MAVEN

Maven是基于项目对象模型(POM),可以通过一小段描述信息来管理项目的构建,报告和文档的软件项目管理工具。

Maven 除了以程序构建能力为特色之外,还提供高级项目管理工具。由于 Maven 的缺省构建规则有较高的可重用性,所以常常用两三行 Maven 构建脚本就可以构建简单的项目。由于 Maven 的面向项目的方法,许多 Apache Jakarta 项目发文时使用 Maven,而且公司项目采用 Maven 的比例在持续增长。

用MAVEN来管理jar包,不用一个一个去添加和下载jar包了,直接在maven配置文件中配置就可以了,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的类库

右键工程–>properties–>JAVA Build Path–>Edit

在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/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/mvc http://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/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/mvc http://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&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_user
where 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;
}
@Override
public 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模板类
*/
@Resource
protected 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 {

@Override
public UserBean findById(int id) {
// 测试切面类是否完成错误记录进入数据库时,解除注释
// throw new NullPointerException();
return session.selectOne("user.findById", id);
}

@Override
public 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文件
*/
@Before
public 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();
}
}
/**
* 销毁
*/
@After
public 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.Test
public 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 {
/**
* 注入的业务接口
*/
@Resource
private 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")
@ResponseBody
private 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.最后

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

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

MAVEN环境变量的配置,在path中加入%MAVEN_HOME%\bin;如果还需要配置jar包的仓库可以参看博文MyEclipse+Tomcat+MAVEN+SVN项目完整环境搭建

对于SqlSession报错的问题,要加多例

对于Spring配置文件读取jdbc.properties文件时,报错,有可能是mySQL的权限验证问题,它会默认使用系统的userName,解决方案有两种,一种参看博文mysql启动问题access denied for user ‘root’@’localhost’(using password:YES) 另一种是找到mysql安装目录,在my.ini中,以记事本打开的文末添加–skip-grant-tables

对于Spring版本较低的,Json,可以用如下依赖

org.codehaus.jackson

jackson-mapper-asl

1.9.13

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

Myeclipse GA 2014的下载门,做为程序员肯定要用最新版的哇,遇到问题去解决就是了,不要怕遇到问题而用旧版,很多过时方法和不支持的东西,新的东西,永远更多插件支持,永远兼容旧版http://www.my-eclipse.cn/

如果有兴趣,可以关注我的CSDN http://blog.csdn.net/kang82651204/

本文源码:

http://download.csdn.net/detail/kang82651204/9412243
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息