Spring是分层的Java平台应用一站式的轻量级开源框架,以反转控制(Inversion of Control,IoC)和面向切面编程(Aspect Oriented Programming,AOP)为内核,提供了展现层SpringMVC、持久层SpringJDBC以及业务层事务管理等众多企业级应用技术,此外Spring还整合了中国第三方框架和类库。

    Spring给我们带来以下几个好处:

  • 方便解耦,简化开发。通过Spring提供的IoC容器,可以将对象之间的依赖关系交由Spring进行控制,避免硬编码所造成的过度程序耦合。

  • AOP编程的支持。通过Spring提供的AOP功能,用户可以方便地进行面向切面编程

  • 声明式事务。在Spring中,用户可以从单调烦闷的事务管理代码中解脱出来,通过声明式事务灵活地进行事务管理,提高开发效率和质量

  • 方便程序的测试。可以用非容器依赖的编程方式进行所有的测试工作。

  • 方便集成各种优秀的框架。Spring是非***是框架,能够整合其他优秀框架,如Struts、Hibernate、Quartz等

  • 降低JavaEEAPI的使用难度。Spring为JavaEE API(如JDBC、JavaMail和JMS等)提供了一个薄薄的封装层,通过Spring的简易封装,大大降低了这些JavaEE API的使用难度

  • Spring是开源项目,并且是源码是Java技术的最佳实践规范。

    Spring的组成:IoC、AOP、数据访问和继承、Web及远程调用以及测试框架。

  • IoC,Spring核心模块实现了IoC的功能,它将类和类之间的依赖从代码中脱离出来,用配置的方式进行依赖关系描述,由IoC容器负责依赖类之间的创建、拼接、管理和获取等工作。BeanFactory接口是Spring框架的核心接口,它实现了容器的许多核心功能。Context模块构建于BeanFactory之上,扩展了BeanFactory的功能。提供了邮件服务、任务调度以及JNDI定位、远程访问等。ApplicationContext是Context模块的核心接口。

  • AOP模块,AOP是进行横切逻辑编程的思想。在AOP模块里,Spring提供了满足AOP Alliance规范的实现,此外和整合了AspectJ这种AOP语言级的框架。

  • 数据访问和集成。任何应用程序的核心问题都是对数据的访问和操作。数据有很多表现形式,如数据表、XML、消息等。Spring站在DAO的抽象层面,简历了一套面向DAO层统一的异常体系。其次,Spring通过模板化技术对各种数据访问技术进行了薄层封装,将模式化的代码隐藏起来,是数据访问的程序得到大幅简化。这样Spring就建立起了和数据形式及访问技术无关的统一的DAO层,借助AOP技术,Spring提供了声明式事务的功能。

  • Web及远程访问。Spring提供了MVC,SpringMVC类似于StrutsMVC框架。此外Spring在远程访问以及WebService上提供了很多著名框架的整合。

本章将通过一个登陆示例来演示SpringMVC。

1、准备工作,创建数据库和数据表

DROP DATABASE IF EXISTS spring_src;
CREATE DATABASE spring_src DEFAULT CHARACTER SET utf8;
CREATE USER 'spring_src'@'localhost' IDENTIFIED BY 'spring_src';
GRANT ALL ON spring_src.* TO 'spring_src'@'localhost';
USE spring_src;

##创建用户表
CREATE TABLE t_user (
   user_id   INT AUTO_INCREMENT PRIMARY KEY,
   user_name VARCHAR(30),
   password  VARCHAR(32),
   last_visit datetime,
   last_ip  VARCHAR(23)
)ENGINE=InnoDB; 

##创建用户登录日志表
CREATE TABLE t_login_log (
   login_log_id  INT AUTO_INCREMENT PRIMARY KEY,
   user_id   INT,
   ip  VARCHAR(23),
   login_datetime datetime
)ENGINE=InnoDB; 

##插入初始化数据
INSERT INTO t_user (user_name,password) 
             VALUES('admin','123456');
COMMIT;

2、创建的工程如下:

Spring快速上手_第1张图片

maven项目sprProject的主目录的pom文件内容:


    4.0.0
    com.smart
    chapter
    pom
    3.1-SNAPSHOT
    Spring3.1 
    Spring3.1
    
        UTF-8
        1.6
        3.1-SNAPSHOT
        3.1.1.RELEASE
        5.1.6
        1.2.2
        1.6.9
        1.1.1
        3.2.1
        3.9.0.GA
        1.8.3
        1.6.2
        3.6.10.Final
        4.0.2.GA
        1.6.1

        1.2.1
        2.0
        2.5
        1.2
        1.1.2
        2.3.8
        6.1.5

        1.8.5
        4.9.0
        6.3.1
        3.1
        2.4.8
    
    
        chapter1
    
    
        
            
                maven-surefire-plugin
                
                    true
                
            
        
    

chapter1的pom文件配置依赖关系


    
        com.smart
        chapter
        3.1-SNAPSHOT
    
    4.0.0
    chapter1
    3.1-SNAPSHOT
    第一章示例
    Spring 快速入门
    war
    
        
        
            org.springframework
            spring-beans
            ${org.springframework.version}
        
        
            org.springframework
            spring-jdbc
            ${org.springframework.version}
        
        
            org.springframework
            spring-web
            ${org.springframework.version}
        
        
            org.springframework
            spring-webmvc
            ${org.springframework.version}
        
        
        
            mysql
            mysql-connector-java
            ${mysql.version}
        
        
        
            commons-dbcp
            commons-dbcp
            ${commons-dbcp.version}
        
        
            org.aspectj
            aspectjweaver
            ${aspectjweaver.version}
        
        
            org.apache.commons
            com.springsource.org.apache.commons.logging
            ${apache.commons.version}
        
        
            fakepath
            com.springsource.net.sf.cglib
            2.1.3
        
        
        
            javax.servlet.jsp
            jsp-api
            ${jsp-api.version}
            provided
        
        
            taglibs
            standard
            ${standard.version}
            runtime
        
        
            javax.servlet
            servlet-api
            ${servlet-api.version}
        
        
            javax.servlet
            jstl
            ${jstl.version}
        
        
        
            org.springframework
            spring-test
            ${org.springframework.version}
        
        
            org.testng
            testng
            ${testng.version}
        
    
    
        chapter1
        
            
                maven-surefire-plugin
                
                    true
                
            
            
            
                org.mortbay.jetty
                maven-jetty-plugin
                6.1.5
                
                    src/main/webapp
                    3
                    /chapter1
                    
                        
                            8088
                        
                    
                
            
        
    

chapter项目的目录结构

Spring快速上手_第2张图片

相对应的代码如下:

domain(领域对象)包代码如下:

package com.smart.domain;

import java.io.Serializable;
import java.util.Date;

public class User implements Serializable {
    private int userId;

    private String userName;

    private String password;

    private String lastIp;

    private Date lastVisit;

    public String getLastIp() {
        return lastIp;
    }

    public void setLastIp(String lastIp) {
        this.lastIp = lastIp;
    }

    public Date getLastVisit() {
        return lastVisit;
    }

    public void setLastVisit(Date lastVisit) {
        this.lastVisit = lastVisit;
    }

    public int getUserId() {
        return userId;
    }

    public void setUserId(int userId) {
        this.userId = userId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

}

package com.smart.domain;

import java.io.Serializable;
import java.util.Date;

public class LoginLog implements Serializable {
    private int loginLogId;

    private int userId;

    private String ip;

    private Date loginDate;

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public Date getLoginDate() {
        return loginDate;
    }

    public void setLoginDate(Date loginDate) {
        this.loginDate = loginDate;
    }

    public int getLoginLogId() {
        return loginLogId;
    }

    public void setLoginLogId(int loginLogId) {
        this.loginLogId = loginLogId;
    }

    public int getUserId() {
        return userId;
    }

    public void setUserId(int userId) {
        this.userId = userId;
    }

}

dao(持久层)代码如下:

package com.smart.dao;

import java.sql.ResultSet;
import java.sql.SQLException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowCallbackHandler;
import org.springframework.stereotype.Repository;

import com.smart.domain.User;

@Repository
public class UserDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;


    public int getMatchCount(String userName, String password) {
        String sqlStr = " SELECT count(*) FROM t_user "
                + " WHERE user_name =? and password=? ";
        return jdbcTemplate.queryForInt(sqlStr, new Object[]{userName, password});
    }

    public User findUserByUserName(final String userName) {
        String sqlStr = " SELECT user_id,user_name "
                + " FROM t_user WHERE user_name =? ";
        final User user = new User();
        jdbcTemplate.query(sqlStr, new Object[]{userName},
                new RowCallbackHandler() {
                    public void proce***ow(ResultSet rs) throws SQLException {
                        user.setUserId(rs.getInt("user_id"));
                        user.setUserName(userName);
                    }
                });
        return user;
    }

    public void updateLoginInfo(User user) {
        String sqlStr = " UPDATE t_user SET last_visit=?,last_ip=?"
                + " WHERE user_id =?";
        jdbcTemplate.update(sqlStr, new Object[]{user.getLastVisit(),
                user.getLastIp(), user.getUserId()});
    }
}

package com.smart.dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import com.smart.domain.LoginLog;

@Repository
public class LoginLogDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    public void insertLoginLog(LoginLog loginLog) {
        String sqlStr = "INSERT INTO t_login_log(user_id,ip,login_datetime) "
                + "VALUES(?,?,?)";
        Object[] args = {loginLog.getUserId(), loginLog.getIp(),
                loginLog.getLoginDate()};
        jdbcTemplate.update(sqlStr, args);
    }
}

在Spring中装配dao, 本案例在applicationContext.xml配置中装配dao


    
    
    
    
    
    
   

   
   
      
   
   
      
   
   
      
      
   
   
      
         
      
   

业务层(service)代码:

package com.smart.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.smart.dao.LoginLogDao;
import com.smart.dao.UserDao;
import com.smart.domain.LoginLog;
import com.smart.domain.User;

@Service
public class UserService {

    @Autowired
    private UserDao userDao;

    @Autowired
    private LoginLogDao loginLogDao;

    public boolean hasMatchUser(String userName, String password) {
        int matchCount = userDao.getMatchCount(userName, password);
        return matchCount > 0;
    }

    public User findUserByUserName(String userName) {
        return userDao.findUserByUserName(userName);
    }

    public void loginSuccess(User user) {
        LoginLog loginLog = new LoginLog();
        loginLog.setUserId(user.getUserId());
        loginLog.setIp(user.getLastIp());
        loginLog.setLoginDate(user.getLastVisit());
        loginLogDao.insertLoginLog(loginLog);
    }

}

在Spring中装配Service,具体内容将applicationContext.xml。


单元测试。TestNG是一种基于注解的新一代单元测试框架,通过添加灵活的配置、测试分类和参数设置以及依赖测试等特性来克服JUnit的不足之处。首先在pom.xml文件中配置testNG、Spring-test的两个类的依赖。详见chapter1项目下的pom.xml。

单元测试模块结构:

Spring快速上手_第3张图片

单元测试代码如下:

package com.smart.service;


import java.util.Date;


import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.annotations.*;

import static org.testng.Assert.*;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import com.smart.domain.User;

@ContextConfiguration(locations = {"/applicationContext.xml"})
public class UserServiceTest extends AbstractTestNGSpringContextTests {

    @Autowired
    private UserService userService;

    @Test
    public void hasMatchUser() {
        boolean b1 = userService.hasMatchUser("admin", "123456");
        boolean b2 = userService.hasMatchUser("admin", "1111");
        assertTrue(b1);
        assertTrue(!b2);
    }

    @Test
    public void findUserByUserName() {
        User user = userService.findUserByUserName("admin");
        assertEquals(user.getUserName(), "admin");
    }

    @Test
    public void loginSuccess() {
        User user = userService.findUserByUserName("admin");
        user.setUserId(1);
        user.setUserName("admin");
        user.setLastIp("192.168.12.7");
        user.setLastVisit(new Date());
        userService.loginSuccess(user);
    }
}

package com.smart.dao;


import com.smart.domain.User;
import com.smart.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.annotations.Test;

import java.util.Date;

import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;

@ContextConfiguration(locations = {"/applicationContext.xml"})
public class UserDaoTest extends AbstractTestNGSpringContextTests {

    @Autowired
    private UserDao userDao;

    @Test
    public void hasMatchUser() {
        int count  = userDao.getMatchCount("admin", "123456");
        assertTrue(count>0);
    }

    @Test
    public void findUserByUserName() {
        User user = userDao.findUserByUserName("admin");
        assertNotNull(user);
        assertEquals(user.getUserName(), "admin");
    }

}

package com.smart.web;

import com.smart.domain.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;

@ContextConfiguration(locations = {"classpath:applicationContext.xml","file:d:/actionSpring/chapter/chapter1/src/main/webapp/WEB-INF/viewspace-servlet.xml"})
public class LoginControllerTest extends AbstractTestNGSpringContextTests {
    @Autowired
    private AnnotationMethodHandlerAdapter handlerAdapter;
    @Autowired
    private LoginController controller;
   //声明Request与Response模拟对象
   private MockHttpServletRequest request;
   private MockHttpServletResponse response;

   //执行测试前先初始模拟对象
   @BeforeMethod
   public void before() {
      request = new MockHttpServletRequest();
      request.setCharacterEncoding("UTF-8");
      response = new MockHttpServletResponse();
        request.setAttribute(HandlerMapping.INTROSPECT_TYPE_LEVEL_MAPPING, true); //Spring3.1 存在的BUG

   }

   // 测试LoginController#loginCheck()方法
   @Test
   public void loginCheck() throws Exception {
        //测试登陆成功的情况
       request.setRequestURI("/admin/loginCheck.html");
      request.addParameter("userName", "admin"); // 设置请求URL及参数
      request.addParameter("password", "123456");

      //向控制发起请求 ” /loginCheck.html”
      ModelAndView mav = handlerAdapter.handle(request, response, controller);
      User user = (User) request.getSession().getAttribute("user");
      assertNotNull(mav);
      assertEquals(mav.getViewName(), "main");
      assertNotNull(user);
        request.getSession().removeAttribute("user");

        //测试登陆失败的情况
        request.setRequestURI("/admin/loginCheck.html");
        request.addParameter("userName", "test");
        request.addParameter("password", "123456");

        mav = handlerAdapter.handle(request, response, controller);
        user = (User) request.getSession().getAttribute("user");
        assertNotNull(mav);
        assertEquals(mav.getViewName(), "login");
        assertNull(user);

   }
}

示例更多内容及运行结果请见附件