zoukankan      html  css  js  c++  java
  • spring学习总结(mybatis,事务,测试JUnit4,日志log4j&slf4j,定时任务quartz&spring-task,jetty,Restful-jersey等)

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

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

    在项目的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 {}: 
    {}", 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

  • 相关阅读:
    递归的小实例
    try-catch-finally实例
    集合的排序(正序,倒序,从大到小排序)
    数组的排序(sort和冒泡)
    拦截器的使用,不登录用户不能进行其他操作
    把日志从数据库导出到Excel表格中(poi)
    Java 对Excel进行导入操作
    java 面试题集锦
    端口被占用解决办法
    (转)Java 最常见的 200+ 面试题汇总
  • 原文地址:https://www.cnblogs.com/softidea/p/5668651.html
Copyright © 2011-2022 走看看