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
相关文章推荐
- maven学习
- 一个jar包里的网站
- 一个jar包里的网站之文件上传
- 一个jar包里的网站之返回对媒体类型
- maven插件maven-war-plugin的使用
- jenkins------部署项目到jboss eap下
- maven使用经验集
- XML 与 JSON 优劣对比
- Spring整合Quartz(JobDetailBean方式)
- Spring整合Quartz(JobDetailBean方式)
- VBA将excel数据表生成JSON文件
- newtonsoft.json解析天气数据出错解决方法
- vbs 解析json jsonp的方法
- Extjs4如何处理后台json数据中日期和时间
- C#实现将类的内容写成JSON格式字符串的方法
- JQuery ajax返回JSON时的处理方式 (三种方式)
- jquery JSON的解析方式示例介绍
- c#版json数据解析示例分享
- ASP JSON类文件的使用方法
- C#实现对Json字符串处理实例