spring學習總結(mybatis,事務,測試JUnit4,日誌log4j&slf4j,定時任務quartz&spring-task,jetty,Restful-jersey等)

    在實戰中學習,模仿博客園的部分功能。包括用戶的註冊,登錄;發表新隨筆,閱讀隨筆;發表評論,以及定時任務等。Entity層設計3張表,分別爲user表(用戶),essay表(隨筆)以及comment表(評論)。表結構以下:php

項目開發採用Intellij IDEA + maven,整個項目結構以下以下圖所示: html

在項目的pom.xml文件中,導入項目須要的依賴。pom.xml內容以下所示:java

  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文件中導入相關依賴。以後文章中再也不說明。mysql

 

下面開始詳細介紹。 git

1、Mybatisgithub

一、先作準備工做。在mysql數據庫中建立表。web

 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

二、在entity目錄下建立與數據庫中表對應的類,以user表爲例。spring

 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

三、在dao目錄下建立操做數據表的接口,以userDao爲例。sql

 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

四、爲使用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>

五、準備工做已經完成,如今就能夠經過在**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>

六、更多關於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魔法堂:即學即用篇

 

2、事務

在spring中實現事務能夠很簡單。只須要配置好事務管理器,以後給須要事務處理的類或者方法直接經過@Transactional註解便可。

一、在本項目中,經過在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" />

二、給須要事務處理的類或者方法經過@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 }

 

3、JUnit4測試

使用JUnit4能夠很方便的進行單元測試。假設咱們須要對UserService類中的各個方法進行測試,只須要在test/com/everSeeker/service目錄下新建測試類TestUserService便可。

一、在測試類前面新增2個註解:

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations = {"/spring.xml"})

@RunWith:加載JUnit4。

@ContextConfiguration:加載spring配置文件,是一個字符串數組,能夠加載多個配置文件。

二、在具體方法前新增註解@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 }

 

4、日誌(log4j & slf4j)

一、關鍵是配置好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/

二、直接使用便可,以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 }

 

5、定時任務(Quartz & spring-task)

主要介紹目前主流的2種在指定時間執行或者按某個頻率自動執行的實現方式。

一、spring-task:採用@Scheduled註解方式,配置簡單,使用靈活方便。

二、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 }

 

6、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

 

7、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/everseeker0307/spring-demo

相關文章
相關標籤/搜索