你的位置:首页 > Java教程

[Java教程]spring学习总结(mybatis,事务,测试JUnit4,日志log4jslf4j,定时任务quartzspring


    在实战中学习,模仿博客园的部分功能。包括用户的注册,登陆;发表新随笔,阅读随笔;发表评论,以及定时任务等。Entity层设计3张表,分别为user表(用户),essay表(随笔)以及comment表(评论)。表结构如下:

项目开发采用Intellij IDEA + maven,整个项目结构如下如下图所示: 

在项目的pom.

 1 <project ="http://maven.apache.org/POM/4.0.0" ="http://www.w3.org/2001/ 2      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 3   <modelVersion>4.0.0</modelVersion> 4   <groupId>spring_demo2</groupId> 5   <artifactId>com.everSeeker</artifactId> 6   <packaging>war</packaging> 7   <version>1.0</version> 8   <name>com.everSeeker Maven Webapp</name> 9   <url>http://maven.apache.org</url> 10  11   <properties> 12     <spring.version>4.2.4.RELEASE</spring.version> 13     <jetty.version>9.3.7.v20160115</jetty.version> 14     <slf4j.version>1.7.14</slf4j.version> 15     <jersey.version>1.19</jersey.version> 16   </properties> 17  18   <dependencies> 19  20     <!--数据库相关, mysql, mybatis--> 21     <dependency> 22       <groupId>mysql</groupId> 23       <artifactId>mysql-connector-java</artifactId> 24       <version>5.1.38</version> 25     </dependency> 26     <dependency> 27       <groupId>org.mybatis</groupId> 28       <artifactId>mybatis</artifactId> 29       <version>3.3.0</version> 30     </dependency> 31     <dependency> 32       <groupId>org.mybatis</groupId> 33       <artifactId>mybatis-spring</artifactId> 34       <version>1.2.3</version> 35     </dependency> 36  37     <!--数据源配置, dataSource--> 38     <dependency> 39       <groupId>c3p0</groupId> 40       <artifactId>c3p0</artifactId> 41       <version>0.9.1.2</version> 42     </dependency> 43  44     <!--事务相关, transcationManager--> 45     <dependency> 46       <groupId>org.springframework</groupId> 47       <artifactId>spring-jdbc</artifactId> 48       <version>${spring.version}</version> 49     </dependency> 50  51     <!--可以找到使用Spring ApplicationContext特性时所需的全部类,JDNI 所需的全部类,instrumentation组件以及校验Validation 方面的相关类。外部依赖spring-beans, (spring-aop)。--> 52     <!--提供基于注解的配置, 比如@Component, @Service, @Repository, @Controller等--> 53     <dependency> 54       <groupId>org.springframework</groupId> 55       <artifactId>spring-context</artifactId> 56       <version>${spring.version}</version> 57     </dependency> 58     <dependency> 59       <groupId>org.springframework</groupId> 60       <artifactId>spring-context-support</artifactId> 61       <version>${spring.version}</version> 62     </dependency> 63     <dependency> 64       <groupId>org.springframework</groupId> 65       <artifactId>spring-tx</artifactId> 66       <version>${spring.version}</version> 67     </dependency> 68  69     <!--测试--> 70     <dependency> 71       <groupId>junit</groupId> 72       <artifactId>junit</artifactId> 73       <version>4.12</version> 74       <scope>test</scope> 75     </dependency> 76     <dependency> 77       <groupId>org.springframework</groupId> 78       <artifactId>spring-test</artifactId> 79       <version>${spring.version}</version> 80     </dependency> 81  82     <!--任务调度--> 83     <dependency> 84       <groupId>org.quartz-scheduler</groupId> 85       <artifactId>quartz</artifactId> 86       <version>2.2.1</version> 87     </dependency> 88  89     <!--log4j && slf4j--> 90     <dependency> 91       <groupId>org.slf4j</groupId> 92       <artifactId>slf4j-api</artifactId> 93       <version>${slf4j.version}</version> 94     </dependency> 95     <dependency> 96       <groupId>org.slf4j</groupId> 97       <artifactId>slf4j-log4j12</artifactId> 98       <version>${slf4j.version}</version> 99     </dependency>100     <dependency>101       <groupId>org.slf4j</groupId>102       <artifactId>jcl-over-slf4j</artifactId>103       <version>${slf4j.version}</version>104       <scope>runtime</scope>105     </dependency>106 107     <!--jetty相关-->108     <dependency>109       <groupId>org.eclipse.jetty</groupId>110       <artifactId>jetty-server</artifactId>111       <version>${jetty.version}</version>112     </dependency>113     <dependency>114       <groupId>org.eclipse.jetty</groupId>115       <artifactId>jetty-servlet</artifactId>116       <version>${jetty.version}</version>117     </dependency>118     <dependency>119       <groupId>org.eclipse.jetty</groupId>120       <artifactId>jetty-webapp</artifactId>121       <version>${jetty.version}</version>122     </dependency>123     <dependency>124       <groupId>org.eclipse.jetty</groupId>125       <artifactId>jetty-servlets</artifactId>126       <version>${jetty.version}</version>127     </dependency>128 129     <!--jersey-->130     <dependency>131       <groupId>com.sun.jersey</groupId>132       <artifactId>jersey-core</artifactId>133       <version>${jersey.version}</version>134     </dependency>135     <dependency>136       <groupId>com.sun.jersey.contribs</groupId>137       <artifactId>jersey-spring</artifactId>138       <version>${jersey.version}</version>139       <exclusions>140         <exclusion>141           <artifactId>spring-core</artifactId>142           <groupId>org.springframework</groupId>143         </exclusion>144         <exclusion>145           <artifactId>spring-beans</artifactId>146           <groupId>org.springframework</groupId>147         </exclusion>148         <exclusion>149           <artifactId>spring-context</artifactId>150           <groupId>org.springframework</groupId>151         </exclusion>152         <exclusion>153           <artifactId>spring-web</artifactId>154           <groupId>org.springframework</groupId>155         </exclusion>156         <exclusion>157           <artifactId>spring-aop</artifactId>158           <groupId>org.springframework</groupId>159         </exclusion>160       </exclusions>161     </dependency>162     <dependency>163       <groupId>com.sun.jersey</groupId>164       <artifactId>jersey-server</artifactId>165       <version>${jersey.version}</version>166     </dependency>167     <dependency>168       <groupId>com.sun.jersey</groupId>169       <artifactId>jersey-servlet</artifactId>170       <version>${jersey.version}</version>171     </dependency>172     <dependency>173       <groupId>com.sun.jersey</groupId>174       <artifactId>jersey-json</artifactId>175       <version>${jersey.version}</version>176     </dependency>177 178     <!--用来将POJO序列化为JSON对象-->179     <dependency>180       <groupId>org.glassfish.jersey.media</groupId>181       <artifactId>jersey-media-json-jackson</artifactId>182       <version>2.22.2</version>183     </dependency>184 185   </dependencies>186 187   <build>188     <finalName>com.everSeeker</finalName>189   </build>190 191 </project>

注:以下所有介绍,第一步都是在pom.之后文章中不再说明。

 

下面开始详细介绍。 

一、Mybatis

1、先做准备工作。在mysql数据库中创建表。

 1 create database if NOT EXISTS spring_demo default character set utf8; 2 use spring_demo; 3 show engines; 4  5 create table if not exists user(id int primary key not null auto_increment, username varchar(12) not null, password varchar(20), score int, ranking int, essay_count int, UNIQUE(username)) engine=InnoDB; 6 show table status like 'user'\G; 7  8 create table if not exists essay(id int primary key not null auto_increment, title varchar(40) not null, create_date datetime, user_id int, reading_count int, comment_count int, tag varchar(40), UNIQUE(title)) engine=InnoDB; 9 show table status like 'essay'\G;10 11 create table if not exists comment(id int PRIMARY KEY NOT NULL AUTO_INCREMENT, content TEXT, user_id int, essay_id int, comment_date DATETIME) ENGINE=InnoDB;12 show table status like 'comment'\G;

sql

2、在entity目录下创建与数据库中表对应的类,以user表为例。

 1 package com.everSeeker.entity; 2  3 import java.io.Serializable; 4  5 /** 6  * 对象的序列化 class implements Serializable 7  * 参考文档:http://www.cnblogs.com/xudong-bupt/archive/2013/05/19/3086493.html 8 */ 9 public class User implements Serializable {10   private int id;11   private String username;12   private String password;13   private int score;14   private int ranking;15   private int essayCount;16 17   public User() {}18 19   public User(String username, String password) {20     this.username = username;21     this.password = password;22     score = 0;23     ranking = 0;24     essayCount = 0;25   }26 27   public int getId() {28     return id;29   }30 31   public void setId(int id) {32     this.id = id;33   }34 35   public String getUsername() {36     return username;37   }38 39   public void setUsername(String username) {40     this.username = username;41   }42 43   public String getPassword() {44     return password;45   }46 47   public void setPassword(String password) {48     this.password = password;49   }50 51   public int getScore() {52     return score;53   }54 55   public void setScore(int score) {56     this.score = score;57   }58 59   public int getRanking() {60     return ranking;61   }62 63   public void setRanking(int ranking) {64     this.ranking = ranking;65   }66 67   public int getEssayCount() {68     return essayCount;69   }70 71   public void setEssayCount(int essayCount) {72     this.essayCount = essayCount;73   }74 75   @Override76   public String toString() {77     return "User [id=" + id + ", username=" + username + ", password=" + password + ", score=" + score +78         ", rankding=" + ranking + ", essayCount=" + essayCount + "]";79   }80 }

User.java

3、在dao目录下创建操作数据表的接口,以userDao为例。

 1 package com.everSeeker.dao; 2  3 import com.everSeeker.entity.User; 4 import org.apache.ibatis.annotations.Param; 5 import org.springframework.stereotype.Repository; 6  7 @Repository 8 public interface UserDao { 9 10   void addUser(@Param("user") User user);11 12   User getUserById(int id);13 14   User getUserByUsername(String username);15 16   void updateUser(User user);17 18   void rankingByScore();19 }

UserDao.java

4、为使用mybatis管理操作数据库,首先需要设置spring与mybatis配合使用的相关配置。

mybatis.

spring-mybatis.

具体文件内容如下:

 1 <??> 2 <!DOCTYPE configuration 3     PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> 4  5 <configuration> 6  7    <!--配置实体类的别名--> 8    <typeAliases> 9        <!--以下2种方法选其一即可。 第1种方法:使用typeAlias,为单个类设置别名。-->10        <typeAlias type="com.everSeeker.entity.User" alias="User" />11        <typeAlias type="com.everSeeker.entity.Essay" alias="Essay" />12        <typeAlias type="com.everSeeker.entity.Comment" alias="Comment" />13        <!--第2种方法:使用package,为包下面的所有类设置别名,默认规则为com.everSeeker.entity.User设置为User,去除前面的包名。-->14        <!--<package name="com.everSeeker.entity" />-->15    </typeAliases>16 17 </configuration>

mybatis.
 1 <??> 2 <beans ="http://www.springframework.org/schema/beans" 3     ="http://www.w3.org/2001/ 4     ="http://www.springframework.org/schema/tx" 5     ="http://www.springframework.org/schema/p" 6     xsi:schemaLocation="http://www.springframework.org/schema/beans 7              http://www.springframework.org/schema/beans/spring-beans-3.1.xsd 8              http://www.springframework.org/schema/tx 9              http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">10 11    <!--数据源配置 c3p012       常见的数据源实现类包有2个,一个是apache的DBCP(org.apache.commons.dbcp.BasicDataSource),另一个为C3P0。13    -->14    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"15        destroy-method="close">16 17        <property name="driverClass" value="${db.mysql.driverClass}" />18        <property name="jdbcUrl" value="${db.mysql.jdbcUrl}" />19        <property name="user" value="${db.mysql.user}" />20        <property name="password" value="${db.mysql.password}" />21 22        <!--连接池中保留的最小连接数。 -->23        <property name="minPoolSize" value="${db.minPoolSize}" />24 25        <!--连接池中保留的最大连接数。Default: 15 -->26        <property name="maxPoolSize" value="${db.maxPoolSize}" />27 28        <!--初始化时获取的连接数,取值应在minPoolSize与maxPoolSize之间。Default: 3 -->29        <property name="initialPoolSize" value="${db.initialPoolSize}" />30 31        <!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 -->32        <property name="maxIdleTime" value="${db.maxIdleTime}" />33 34        <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 -->35        <property name="acquireIncrement" value="${db.acquireIncrement}" />36 37        <!--JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements 属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。38          如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0 -->39        <property name="maxStatements" value="${db.maxStatements}" />40 41        <!--每60秒检查所有连接池中的空闲连接。Default: 0 -->42        <property name="idleConnectionTestPeriod" value="${db.idleConnectionTestPeriod}" />43 44        <!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 -->45        <property name="acquireRetryAttempts" value="${db.acquireRetryAttempts}" />46 47        <!--获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效 保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试48          获取连接失败后该数据源将申明已断开并永久关闭。Default: false -->49        <property name="breakAfterAcquireFailure" value="${db.breakAfterAcquireFailure}" />50 51        <!--因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的 时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable52          等方法来提升连接测试的性能。Default: false -->53        <property name="testConnectionOnCheckout" value="${db.testConnectionOnCheckout}" />54    </bean>55 56    <!-- myBatis配置.57       classpath和classpath*的区别,参考文档:http://blog.csdn.net/zl3450341/article/details/9306983.58       classpath只会返回第一个匹配的资源,建议确定路径的单个文档使用classpath;匹配多个文档时使用classpath*.59    -->60    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"61        p:dataSource-ref="dataSource"62        p:configLocation="classpath:mybatis.63        p:mapperLocations="classpath*:com/everSeeker/*Mapper. />64 65    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">66        <!--basePackage指定要扫描的包,在此包之下的映射器都会被搜索到。可指定多个包,包与包之间用逗号或分号分隔67          MapperScannerConfigurer将扫描basePackage所指定包下的所有接口类(包括子包),如果他们在SQL映射文件68          中定义过,则将他们动态定义为一个Spring Bean. -->69        <property name="basePackage" value="com.everSeeker.dao" />70        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />71        <!--<property name="annotationClass" value="com.everSeeker.dao" />-->72    </bean>73 74    </beans>

spring-mybatis.

在spring-mybatis.

 1 # Database 2 db.mysql.driverClass = com.mysql.jdbc.Driver 3 db.mysql.jdbcUrl = jdbc:mysql://localhost:3306/spring_demo?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true 4 db.mysql.user = root 5 db.mysql.password = 333 6 db.minPoolSize = 10 7 db.maxPoolSize = 100 8 db.initialPoolSize = 20 9 db.maxIdleTime = 6010 db.acquireIncrement = 511 db.maxStatements = 10012 db.idleConnectionTestPeriod = 6013 db.acquireRetryAttempts = 3014 db.breakAfterAcquireFailure = true15 db.testConnectionOnCheckout = false

db.properties

最后,在spring.

 1 <??> 2 <beans ="http://www.springframework.org/schema/beans" 3     ="http://www.w3.org/2001/ 4     ="http://www.springframework.org/schema/context" 5     xsi:schemaLocation="http://www.springframework.org/schema/beans 6               http://www.springframework.org/schema/beans/spring-beans.xsd 7               http://www.springframework.org/schema/context 8               http://www.springframework.org/schema/context/spring-context.xsd"> 9 10   <!-- 加载Spring配置文件 -->11   <context:property-placeholder location="classpath:db.properties"/>12   <context:property-placeholder location="classpath:log4j.properties"/>13 14   <import resource="classpath:spring-mybatis./>15 16   <!-- 使用spring annotation自动扫描配置 -->17   <context:component-scan base-package="com.everSeeker"/>18   <!-- 自动注入 -->19   <context:annotation-config/>20 21 </beans>

5、准备工作已经完成,现在就可以通过在**Mapper.

 1 <??> 2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 3  4 <mapper namespace="com.everSeeker.dao.UserDao"> 5   <resultMap id="ResultMapUser" type="com.everSeeker.entity.User"> 6     <id column="id" property="id"/> 7     <result column="username" property="username"/> 8     <result column="password" property="password"/> 9     <result column="score" property="score"/>10     <result column="ranking" property="ranking"/>11     <result column="essay_count" property="essayCount"/>12   </resultMap>13 14   <insert id="addUser" parameterType="User">15     INSERT INTO user(username, password, score, ranking, essay_count) VALUES(#{user.username}, #{user.password}, #{user.score}, #{user.ranking}, #{user.essayCount})16   </insert>17 18   <select id="getUserById" parameterType="int" resultMap="ResultMapUser">19     SELECT * FROM user WHERE id=#{id}20   </select>21 22   <select id="getUserByUsername" parameterType="String" resultMap="ResultMapUser">23     SELECT * FROM user where username=#{username}24   </select>25 26   <update id="updateUser" parameterType="User">27     UPDATE user SET username=#{username}, password=#{password}, score=#{score}, ranking=#{ranking}, essay_count=#{essayCount} where id=#{id}28   </update>29 30   <!--在mysql中执行多条语句,可以采用存储过程,如{call proc()};也可以通过连接数据库时设置allowMultiQueries=true来实现-->31   <update id="rankingByScore">32     --     { call proc() }33     SET @row=0;34     UPDATE user SET ranking=(@row:=@row+1) ORDER BY score DESC;35   </update>36 </mapper>

6、更多关于mybatis的内容参考:

1) http://www.mybatis.org/mybatis-3/zh/index.html

2) 如果数据表中的column字段和modal(entity)中定义的类的字段不一致,比如数据库中User表有字段t_username,而在类User中定义字段username,则可以使用ResultMap来代替ResultType。详细信息可参考MyBatis中关于resultType和resultMap的区别以及MyBatis魔法堂:ResultMap详解以及MyBatis魔法堂:即学即用篇。

 

二、事务

在spring中实现事务可以很简单。只需要配置好事务管理器,之后给需要事务处理的类或者方法直接通过@Transactional注解即可。

1、在本项目中,通过在spring-mybatis.

 1 <!-- 事务管理器配置, 使用jdbc事务 --> 2    <bean id="transactionManager" 3        class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 4        <property name="dataSource" ref="dataSource" /> 5    </bean> 6  7    <!-- 使用annotation定义事务,对标注了@Transactional注解的bean进行处理,以织入事务管理切面. 8       默认情况下,自动使用名称为transactionManager的事务管理器。 9       proxy-target-class为true,表示spring将通过创建子类来代理业务类,需要在类路径中添加CGLib.jar类库。-->10    <tx:annotation-driven transaction-manager="transactionManager"11                proxy-target-class="true" />

2、给需要事务处理的类或者方法通过@Transactional注解。以CommentServiceImpl.java为例,对类中所有方法进行事务处理。publicNewComment方法为发表新的评论,需要在comment表中新增一条评论的记录,之后在essay表中对被评论的随笔评论数+1,同时还需要在user表中对随笔的作者score+10分,这3个操作组合成了一个原子操作,需要进行事务处理。

 1 package com.everSeeker.service.impl; 2  3 import com.everSeeker.dao.CommentDao; 4 import com.everSeeker.dao.EssayDao; 5 import com.everSeeker.dao.UserDao; 6 import com.everSeeker.entity.Comment; 7 import com.everSeeker.entity.Essay; 8 import com.everSeeker.entity.User; 9 import com.everSeeker.service.CommentService;10 import org.springframework.stereotype.Service;11 import org.springframework.transaction.annotation.Transactional;12 13 import javax.annotation.Resource;14 15 @Service("commentService")16 @Transactional17 public class CommentServiceImpl implements CommentService {18   @Resource19   private CommentDao commentDao;20   @Resource21   private EssayDao essayDao;22   @Resource23   private UserDao userDao;24 25   public void publishNewComment(Comment comment) {26     //comment表中新增一条记录27     commentDao.addComment(comment);28     //essay表comment_count+129     Essay essay = essayDao.getEssayById(comment.getEssayId());30     if(essay != null) {31       essay.setCommentCount(essay.getCommentCount() + 1);32       essayDao.updateEssay(essay);33       //user表随笔作者对应的记录score+1034       User user = userDao.getUserById(essay.getUserId());35       if(user != null) {36         user.setScore(user.getScore() + 10);37         userDao.updateUser(user);38       }39     }40   }41 }

 

三、JUnit4测试

使用JUnit4可以很方便的进行单元测试。假设我们需要对UserService类中的各个方法进行测试,只需要在test/com/everSeeker/service目录下新建测试类TestUserService即可。

1、在测试类前面新增2个注解:

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations = {"/spring.

@RunWith:加载JUnit4。

@ContextConfiguration:加载spring配置文件,是一个字符串数组,可以加载多个配置文件。

2、在具体方法前新增注解@Test。

TestUserService.java关键内容如下:

 1 package com.everSeeker.service; 2  3 import com.everSeeker.dao.UserDao; 4 import com.everSeeker.entity.User; 5 import org.junit.Test; 6 import org.junit.runner.RunWith; 7 import org.springframework.test.annotation.Rollback; 8 import org.springframework.test.context.ContextConfiguration; 9 import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;10 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;11 12 import javax.annotation.Resource;13 14 15 @RunWith(SpringJUnit4ClassRunner.class)16 @ContextConfiguration(locations = {"/spring.})17 public class TestUserService extends AbstractTransactionalJUnit4SpringContextTests {18 19   @Resource20   private UserService userService;21 22   @Resource23   private UserDao userDao;24 25   /**26    * AbstractTransactionalJUnit4SpringContextTests默认回滚。如果需要修改为不回滚设置为false即可。27    * 默认回滚的主要目的是避免产生脏数据。但是如果数据库主键采取自增模式的话,实质上对数据库还是有一点影响。如果主键采取UUID就没这个问题。28   */29   @Test30   @Rollback(false)31   public void TestAddUser() {32     User user = new User("ponpon7", "888888");33     userService.addUser(user);34   }35 36   @Test37   public void TestGetUserByUsername() {38     System.out.println(userService.getUserByUsername("ppp"));39   }40 }

 

四、日志(log4j & slf4j)

1、关键是配置好log4j.properties文件。

 1 #更多详情请参考: 2 #http://www.cnblogs.com/pigtail/archive/2013/02/16/2913195.html 3 #http://it.oyksoft.com/log4j/ 4  5 #此句为将等级为INFO的日志信息输出到stdout和R这两个目的地,stdout和R的定义在下面的代码,可以任意起名。 6 #等级可分为OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL,如果配置OFF则不打出任何信息, 7 #如果配置为INFO这样只显示INFO, WARN, ERROR的log信息,而DEBUG信息不会被显示,具体讲解可参照第三部分定义配置文件中的logger。 8 log4j.rootCategory = INFO, R, stdout 9 10 #此句为定义名为stdout的输出端是哪种类型,可以是11 #org.apache.log4j.ConsoleAppender(控制台),12 #org.apache.log4j.FileAppender(文件),13 #org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件),14 #org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件)15 #org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)16 log4j.appender.stdout = org.apache.log4j.ConsoleAppender17 18 #此句为定义名为stdout的输出端的layout是哪种类型,可以是19 #org.apache.log4j.HTMLLayout(以HTML表格形式布局),20 #org.apache.log4j.PatternLayout(可以灵活地指定布局模式),21 #org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串),22 #org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息)23 #具体讲解可参照第三部分定义配置文件中的Layout。24 log4j.appender.stdout.layout = org.apache.log4j.PatternLayout25 26 #如果使用pattern布局就要指定的打印信息的具体格式ConversionPattern,打印参数如下:27 #%m 输出代码中指定的消息28 #%p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL29 #%r 输出自应用启动到输出该log信息耗费的毫秒数30 #%c 输出所属的类目,通常就是所在类的全名31 #%t 输出产生该日志事件的线程名32 #%n 输出一个回车换行符,Windows平台为“rn”,Unix平台为“n”33 #%d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyyy MMM dd HH:mm:ss,SSS},输出类似:2002年10月18日 22:10:28,92134 #%l 输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。35 #[QC]是log信息的开头,可以为任意字符,一般为项目简称。36 log4j.appender.stdout.layout.ConversionPattern = [%p]-[%t]-[%l]-[%d{yyyyMMdd HH:mm:ss}]%n%m%n37 38 #将日志信息存入文件中39 log4j.appender.R = org.apache.log4j.DailyRollingFileAppender40 log4j.appender.R.Threshold = INFO41 log4j.appender.R.File = /Users/pingping/Projects/IdeaProjects/cnblogs/spring_demo2/logs/output.log42 log4j.appender.R.DatePattern = '.'yyyy-MM-dd43 log4j.appender.R.Append = true44 log4j.appender.R.layout = org.apache.log4j.PatternLayout45 log4j.appender.R.layout.ConversionPattern = [%p]-[%t]-[%l]-[%d{yyyyMMdd HH:mm:ss}]%n%m%n

更多详细信息可参考:

http://www.cnblogs.com/pigtail/archive/2013/02/16/2913195.html

http://it.oyksoft.com/log4j/

2、直接使用即可,以UserServiceImpl.java为例。

 1 package com.everSeeker.service.impl; 2  3 import com.everSeeker.dao.UserDao; 4 import com.everSeeker.entity.User; 5 import com.everSeeker.service.UserService; 6 import org.slf4j.Logger; 7 import org.slf4j.LoggerFactory; 8 import org.springframework.stereotype.Service; 9 10 import javax.annotation.Resource;11 12 @Service("userService")13 public class UserServiceImpl implements UserService {14   @Resource15   private UserDao userDao;16 17   private static Logger log = LoggerFactory.getLogger(UserServiceImpl.class);18 19   public void addUser(User user) {20     userDao.addUser(user);21   }22 23   public User getUserByUsername(String username) {24     User user = userDao.getUserByUsername(username);25     log.info("All info about {}: \n{}", username, user);26     return user;27   }28 29   public int checkUser(String username, String password) {30     log.info("start check username: {}", username);31     User user = userDao.getUserByUsername(username);32     if (user == null) {33       log.warn("username is incorrect!");34       return 10;35     }36     if (!user.getPassword().equals(password)) {37       log.warn("passowrd is incorrect!");38       return 100;39     }40     log.info("{} has successed checked!", username);41     return 1;42   }43 }

 

五、定时任务(Quartz & spring-task)

主要介绍目前主流的2种在指定时间执行或者按某个频率自动执行的实现方式。

1、spring-task:采用@Scheduled注解方式,配置简单,使用灵活方便。

2、quartz:配置稍微复杂,功能强大。

下面以具体代码详细说明。

首先,新创建spring-task.

 1 <??> 2 <beans ="http://www.springframework.org/schema/beans" 3     ="http://www.w3.org/2001/ 4     ="http://www.springframework.org/schema/task" 5     xsi:schemaLocation="http://www.springframework.org/schema/beans 6               http://www.springframework.org/schema/beans/spring-beans.xsd 7               http://www.springframework.org/schema/task 8               http://www.springframework.org/schema/task/spring-task-3.0.xsd" 9     default-lazy-init="false">10 11    <!--开启定时任务的2种方法,(1)通过spring-task,采用@Scheduled注解方式,配置简单,使用灵活方便;12                 (2)通过quartz,配置稍微复杂,功能强大 -->14 15    <!--方法一:-->16    <!--开启task:annotation-driven,spring可以通过注解@Scheduled来开启任务-->17    <task:executor id="executor" pool-size="5"/>18    <task:scheduler id="scheduler" pool-size="10"/>19    <task:annotation-driven executor="executor" scheduler="scheduler"/>20 21    <!--方法二:-->22    <!--配置作业类-->23    <bean id="quartzTask" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">24        <property name="targetObject">25           <bean class="com.everSeeker.task.QuartzTask"/>26        </property>27        <property name="targetMethod" value="rankingByScore"/>28        <property name="concurrent" value="false"/>29    </bean>30    <!--配置触发器-->31    <!--关于cronExpression, 请参考: http://www.cnblogs.com/yaowen/p/3779284.html-->32    <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">33        <property name="jobDetail" ref="quartzTask"/>34        <!--每隔10s执行一次-->35        <property name="cronExpression" value="0/10 * * * * ?"/>36    </bean>37    <!--配置调度工厂-->38    <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">39        <property name="triggers">40           <list>41               <ref bean="cronTrigger"/>42           </list>43        </property>44    </bean>45 46 </beans>

在com/everSeeker/task目录下新建2个文件QuartzTask.java以及SpringTask.java,分别用来测试quartz以及spring-task。

QuartzTask.java

 1 package com.everSeeker.task; 2  3 import com.everSeeker.dao.UserDao; 4 import org.springframework.stereotype.Service; 5  6 import javax.annotation.Resource; 7  8 @Service 9 public class QuartzTask {10   @Resource11   private UserDao userDao;12 13   public void rankingByScore() {14     System.out.println("通过quartz, 每隔10s执行一次任务。。。");15 //    userDao.rankingByScore();16   }17 }

SpringTask.java

 1 package com.everSeeker.task; 2  3 import com.everSeeker.dao.UserDao; 4 import org.springframework.scheduling.annotation.Scheduled; 5 import org.springframework.stereotype.Component; 6  7 import javax.annotation.Resource; 8  9 @Component("springTask")10 public class SpringTask {11 12   @Resource13   private UserDao userDao;14 15   @Scheduled(cron = "0/20 * * * * ?")16   public void rankingByScoreJob() {17     System.out.println("通过spring-task,每隔20秒执行一次任务。。。");18     System.out.println("----------------------------------------");19 //    userDao.rankingByScore();20   }21 }

 

六、jetty

jetty需要定义Server, Connector以及至少一个handler, ThreadPool可选。

先定义自己的handler,内容是输出"hello jetty"。

 1 public class MyHandler extends AbstractHandler { 2  3   public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) 4     throws IOException, ServletException { 5     response.setContentType("text/html;charset=utf-8"); 6     response.setStatus(HttpServletResponse.SC_OK); 7     baseRequest.setHandled(true); 8     response.getWriter().println("<h1>Hello jetty</h1>"); 9   }10 }

之后在Spring配置文件中将Server,Connector以及Handler配置好即可。

 1 # spring-jetty. 2 <bean id="jetty_server" class="org.eclipse.jetty.server.Server" init-method="start" destroy-method="stop"> 3  4     <!--<property name="threadPool">--> 5       <!--<bean id="defaultThreadPool" >--> 6         <!--<property name="minThreads" value="10"/>--> 7         <!--<property name="maxThreads" value="100"/>--> 8       <!--</bean>--> 9     <!--</property>-->10 11     <property name="connectors">12       <list>13         <bean id="Connector" class="org.eclipse.jetty.server.ServerConnector">14           <constructor-arg name="server"><ref bean="jetty_server"/></constructor-arg>15           <property name="port" value="8080"/>16         </bean>17       </list>18     </property>19 20     <property name="handler">21       <bean id="handlers" class="org.eclipse.jetty.server.handler.HandlerList">22         <property name="handlers">23           <list>24             <bean class="com.everSeeker.jetty.MyHandler"/>25             <!--<bean />-->26             <bean class="org.eclipse.jetty.server.handler.DefaultHandler"/>27           </list>28         </property>29       </bean>30     </property>31 32   </bean>

在网页中打开输入网址, http://localhost:8080,页面显示为"hello jetty"。

更多详情请参考:

http://www.eclipse.org/jetty/documentation/current/index.html

http://hbiao68.iteye.com/blog/2111007

http://www.cnblogs.com/windlaughing/archive/2013/06/07/3125358.html

 

七、Restful(jersey)

实现Restful的框架很多,本案例采用的是jersey.

首先建立一个jetty服务,并指定要处理jersey资源的包名com.everSeeker.action,然后启动jetty。

public class App {  public static void main(String[] args) throws Exception {    Server server = new Server(8080);    ServletHolder servlet = new ServletHolder(ServletContainer.class);    servlet.setInitParameter("com.sun.jersey.config.property.resourceConfigClass", "com.sun.jersey.api.core.PackagesResourceConfig");    servlet.setInitParameter("com.sun.jersey.config.property.packages", "com.everSeeker");    ServletContextHandler handler = new ServletContextHandler(ServletContextHandler.SESSIONS);    handler.setContextPath("/");    handler.addServlet(servlet, "/*");    server.setHandler(handler);    server.start();    server.join();  }}

之后在包com.everSeeker.action下新建Restful类,以UserAction.java为例。

 1 @Component 2 @Path("/user") 3 public class UserAction { 4  5   /** 6    * 如果userService不采用getBean方式获得的话,即直接写成private UserService userService,会报空指针错误。 7    * 通过debug方式查看会发现,userService=null,没有注入成功,原因暂时还不知道,请高手告知。 8   */ 9   @Resource10   private UserService userService = SpringContextUtils.getApplicationContext().getBean(UserServiceImpl.class);11 12   /**13    * @GET : get请求14    * @Path : 路径,由于类的路径为/user,所以该方法的路径为/user/{username}15    * @Produces : 返回类型。该方法为文本。16    * @Consumes : 可以接受的类型。17   */18   @GET19   @Path("{username}")20   @Produces(MediaType.TEXT_PLAIN)21   public String getByUsername(@PathParam("username") String username) throws Exception {22     return userService.getUserByUsername(username).toString();23   }24 25   /**26    * 返回的类型为json。需要将类User转换为json格式。本案例采用的转换方式为jackson, 在pom.27   */28   @GET29   @Path("json/{username}")30   @Produces(MediaType.APPLICATION_JSON)31   public User getUserByUsername(@PathParam("username") String username) throws Exception {32     return userService.getUserByUsername(username);33   }34 }

更多信息请参考:

https://jersey.java.net/nonav/documentation/latest/index.html

http://www.zhaochao.net/index.php/2015/12/07/5/

http://waylau.com/jersey-2-spring-4-rest/

 

代码清单请见个人github。地址:https://github.com/ponpon7/spring_demo2。