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、创建的工程如下:
maven项目sprProject的主目录的pom文件内容:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.smart</groupId> <artifactId>chapter</artifactId> <packaging>pom</packaging> <version>3.1-SNAPSHOT</version> <name>Spring3.1 </name> <description>Spring3.1</description> <properties> <file.encoding>UTF-8</file.encoding> <java.version>1.6</java.version> <spring.action.version>3.1-SNAPSHOT</spring.action.version> <org.springframework.version>3.1.1.RELEASE</org.springframework.version> <mysql.version>5.1.6</mysql.version> <commons-dbcp.version>1.2.2</commons-dbcp.version> <aspectjweaver.version>1.6.9</aspectjweaver.version> <apache.commons.version>1.1.1</apache.commons.version> <commons-collections.version>3.2.1</commons-collections.version> <javassist.version>3.9.0.GA</javassist.version> <commons-beanutils.version>1.8.3</commons-beanutils.version> <ehcache.version>1.6.2</ehcache.version> <hibernate.version>3.6.10.Final</hibernate.version> <hibernate-validator.version>4.0.2.GA</hibernate-validator.version> <slf4j-jdk14.version>1.6.1</slf4j-jdk14.version> <commons-fileupload.version>1.2.1</commons-fileupload.version> <jsp-api.version>2.0</jsp-api.version> <servlet-api.version>2.5</servlet-api.version> <jstl.version>1.2</jstl.version> <standard.version>1.1.2</standard.version> <freemarker.version>2.3.8</freemarker.version> <jetty.version>6.1.5</jetty.version> <mockito-all.version>1.8.5</mockito-all.version> <junit.version>4.9.0</junit.version> <testng.version>6.3.1</testng.version> <unitils.version>3.1</unitils.version> <dbunit.version>2.4.8</dbunit.version> </properties> <modules> <module>chapter1</module> </modules> <build> <plugins> <plugin> <artifactId>maven-surefire-plugin</artifactId> <configuration> <skip>true</skip> </configuration> </plugin> </plugins> </build> </project>
chapter1的pom文件配置依赖关系
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <groupId>com.smart</groupId> <artifactId>chapter</artifactId> <version>3.1-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>chapter1</artifactId> <version>3.1-SNAPSHOT</version> <name>第一章示例</name> <description>Spring 快速入门</description> <packaging>war</packaging> <dependencies> <!--① 依赖的Spring模块类库 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${org.springframework.version}</version> </dependency> <!--② 依赖的持久化类库--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> <!--③ 依赖的公共类库--> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>${commons-dbcp.version}</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>${aspectjweaver.version}</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>com.springsource.org.apache.commons.logging</artifactId> <version>${apache.commons.version}</version> </dependency> <dependency> <groupId>fakepath</groupId> <artifactId>com.springsource.net.sf.cglib</artifactId> <version>2.1.3</version> </dependency> <!--④ 依赖的WEB类库--> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>${jsp-api.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>taglibs</groupId> <artifactId>standard</artifactId> <version>${standard.version}</version> <scope>runtime</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>${servlet-api.version}</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>${jstl.version}</version> </dependency> <!--⑤ 依赖的测试类库--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>${testng.version}</version> </dependency> </dependencies> <build> <finalName>chapter1</finalName> <plugins> <plugin> <artifactId>maven-surefire-plugin</artifactId> <configuration> <skip>true</skip> </configuration> </plugin> <!-- jetty插件 --> <plugin> <groupId>org.mortbay.jetty</groupId> <artifactId>maven-jetty-plugin</artifactId> <version>6.1.5</version> <configuration> <webAppSourceDirectory>src/main/webapp</webAppSourceDirectory> <scanIntervalSeconds>3</scanIntervalSeconds> <contextPath>/chapter1</contextPath> <connectors> <connector implementation="org.mortbay.jetty.nio.SelectChannelConnector"> <port>8088</port> </connector> </connectors> </configuration> </plugin> </plugins> </build> </project>
chapter项目的目录结构
相对应的代码如下:
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 processRow(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
<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd"> <!-- 扫描类包,将标注Spring注解的类自动转化Bean,同时完成Bean的注入 --> <context:component-scan base-package="com.smart.dao"/> <context:component-scan base-package="com.smart.service"/> <!-- 配置数据源 --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" p:driverClassName="com.mysql.jdbc.Driver" p:url="jdbc:mysql://localhost:3306/sampledb31" p:username="root" p:password="" /> <!-- 配置Jdbc模板 --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" p:dataSource-ref="dataSource" /> <!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" p:dataSource-ref="dataSource" /> <!-- 通过AOP配置提供事务增强,让service包下所有Bean的所有方法拥有事务 --> <aop:config proxy-target-class="true"> <aop:pointcut id="serviceMethod" expression=" execution(* com.smart.service..*(..))" /> <aop:advisor pointcut-ref="serviceMethod" advice-ref="txAdvice" /> </aop:config> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="*" /> </tx:attributes> </tx:advice> </beans>
业务层(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。
单元测试模块结构:
单元测试代码如下:
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); } }
示例更多内容及运行结果请见附件
时间: 2024-10-08 22:05:34