转载

spring学习总结(mybatis,事务,测试JUnit4,日志log4j&slf4j,定时任务quartz&spring-task,jett...

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

spring学习总结(mybatis,事务,测试JUnit4,日志log4j&slf4j,定时任务quartz&spring-task,jett...

spring学习总结(mybatis,事务,测试JUnit4,日志log4j&slf4j,定时任务quartz&spring-task,jett...

spring学习总结(mybatis,事务,测试JUnit4,日志log4j&slf4j,定时任务quartz&spring-task,jett...

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

spring学习总结(mybatis,事务,测试JUnit4,日志log4j&slf4j,定时任务quartz&spring-task,jett...

在项目的pom.xml文件中,导入项目需要的依赖。pom.xml内容如下所示:

   1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   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.xml文件中导入相关依赖。之后文章中不再说明。

下面开始详细介绍。

一、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     @Override 76     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.xml:在本项目中,仅仅用作给实体类配置别名。

spring-mybatis.xml:在本项目中,用来配置数据源dataSource,sqlSessionFactory等。

具体文件内容如下:

   1 <?xml version="1.0" encoding="UTF-8" ?>  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.xml
   1 <?xml version="1.0" encoding="UTF-8"?>  2 <beans xmlns="http://www.springframework.org/schema/beans"  3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  4        xmlns:tx="http://www.springframework.org/schema/tx"  5        xmlns:p="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        <!--数据源配置 c3p0 12            常见的数据源实现类包有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或automaticTestTable 52                   等方法来提升连接测试的性能。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.xml" 63              p:mapperLocations="classpath*:com/everSeeker/*Mapper.xml" /> 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.xml

在spring-mybatis.xml文件中,引入了db.properties文件中的内容。

   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 = 60 10 db.acquireIncrement = 5 11 db.maxStatements = 100 12 db.idleConnectionTestPeriod = 60 13 db.acquireRetryAttempts = 30 14 db.breakAfterAcquireFailure = true 15 db.testConnectionOnCheckout = false  db.properties

最后,在spring.xml配置文件中载入与mybatis相关的配置文件。

  1 <?xml version="1.0" encoding="UTF-8"?>  2 <beans xmlns="http://www.springframework.org/schema/beans"  3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  4        xmlns:context="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.xml"/> 15  16     <!-- 使用spring annotation自动扫描配置 --> 17     <context:component-scan base-package="com.everSeeker"/> 18     <!-- 自动注入 --> 19     <context:annotation-config/> 20  21 </beans> 

5、准备工作已经完成,现在就可以通过在**Mapper.xml文件中以直接写sql语句的方式来操作数据库并同时实现dao层中相关类的接口了。以UserDao为例,在resources/com/everSeeker目录下创建对应的UserMapper.xml文件。

  1 <?xml version="1.0" encoding="UTF-8"?>  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.xml文件中配置事务管理。

  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 @Transactional 17 public class CommentServiceImpl implements CommentService { 18     @Resource 19     private CommentDao commentDao; 20     @Resource 21     private EssayDao essayDao; 22     @Resource 23     private UserDao userDao; 24  25     public void publishNewComment(Comment comment) { 26         //comment表中新增一条记录 27         commentDao.addComment(comment); 28         //essay表comment_count+1 29         Essay essay = essayDao.getEssayById(comment.getEssayId()); 30         if(essay != null) { 31             essay.setCommentCount(essay.getCommentCount() + 1); 32             essayDao.updateEssay(essay); 33             //user表随笔作者对应的记录score+10 34             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.xml"})

@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.xml"}) 17 public class TestUserService extends AbstractTransactionalJUnit4SpringContextTests { 18  19     @Resource 20     private UserService userService; 21  22     @Resource 23     private UserDao userDao; 24  25     /** 26      * AbstractTransactionalJUnit4SpringContextTests默认回滚。如果需要修改为不回滚设置为false即可。 27      * 默认回滚的主要目的是避免产生脏数据。但是如果数据库主键采取自增模式的话,实质上对数据库还是有一点影响。如果主键采取UUID就没这个问题。 28      */ 29     @Test 30     @Rollback(false) 31     public void TestAddUser() { 32         User user = new User("ponpon7", "888888"); 33         userService.addUser(user); 34     } 35  36     @Test 37     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.ConsoleAppender 17  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.PatternLayout 25  26 #如果使用pattern布局就要指定的打印信息的具体格式ConversionPattern,打印参数如下: 27 #%m 输出代码中指定的消息 28 #%p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL 29 #%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,921 34 #%l 输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。 35 #[QC]是log信息的开头,可以为任意字符,一般为项目简称。 36 log4j.appender.stdout.layout.ConversionPattern = [%p]-[%t]-[%l]-[%d{yyyyMMdd HH:mm:ss}]%n%m%n 37  38 #将日志信息存入文件中 39 log4j.appender.R = org.apache.log4j.DailyRollingFileAppender 40 log4j.appender.R.Threshold = INFO 41 log4j.appender.R.File = /Users/pingping/Projects/IdeaProjects/cnblogs/spring_demo2/logs/output.log 42 log4j.appender.R.DatePattern = '.'yyyy-MM-dd 43 log4j.appender.R.Append = true 44 log4j.appender.R.layout = org.apache.log4j.PatternLayout 45 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     @Resource 15     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.xml配置文件,具体内容如下:

  1 <?xml version="1.0" encoding="UTF-8"?>  2 <beans xmlns="http://www.springframework.org/schema/beans"  3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  4        xmlns:task="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     @Resource 11     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     @Resource 13     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.xml  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" class="org.eclipse.jetty.util.thread.QueuedThreadPool">-->  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 class="com.everSeeker.jetty.RestfulHandler"/>--> 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     @Resource 10     private UserService userService = SpringContextUtils.getApplicationContext().getBean(UserServiceImpl.class); 11  12     /** 13      * @GET : get请求 14      * @Path : 路径,由于类的路径为/user,所以该方法的路径为/user/{username} 15      * @Produces : 返回类型。该方法为文本。 16      * @Consumes : 可以接受的类型。 17      */ 18     @GET 19     @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.xml中有说明。 27      */ 28     @GET 29     @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。

原文  http://www.cnblogs.com/everSeeker/p/5188840.html
正文到此结束
Loading...