Spring学习进阶(一)初识Spring

时间:2021-03-06 04:28:13
 <?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>
<!--<module>chapter2</module>
<module>chapter3</module>
<module>chapter4</module>
<module>chapter5</module>
<module>chapter6</module>
<module>chapter7</module>
<module>chapter8</module>
<module>chapter9</module>
<module>chapter11</module>-->
</modules>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>

chapter:pom.xml

 <?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>
<!--④ 依赖的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>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1</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>

chapter1 pom.xml

 package com.smart.domain;

 import java.io.Serializable;
import java.util.*;
/**
* Created by sanglp on 2016/6/29.
*/ /**
* domain对象一般要实现Serializable接口,以便进行序列化
*/
public class User implements Serializable {
private int userId;
private String userName;
private String password;
private String lastIp;
private Date lastVisit; public int getUserId() {
return userId;
} public String getUserName() {
return userName;
} public String getPassword() {
return password;
} public String getLastIp() {
return lastIp;
} public Date getLastVisit() {
return lastVisit;
} public void setUserId(int userId) {
this.userId = userId;
} public void setUserName(String userName) {
this.userName = userName;
} public void setPassword(String password) {
this.password = password;
} public void setLastIp(String lastIp) {
this.lastIp = lastIp;
} public void setLastVisit(Date lastVisit) {
this.lastVisit = lastVisit;
}
}

User.java

 package com.smart.domain;

 /**
* Created by sanglp on 2016/6/29.
*/
import java.util.*;
public class LoginLog {
private int loginLogId;
private int userId;
private String ip;
private Date loginDate; public int getLoginLogId() {
return loginLogId;
} public int getUserId() {
return userId;
} public String getIp() {
return ip;
} public Date getLoginDate() {
return loginDate;
} public void setLoginLogId(int loginLogId) {
this.loginLogId = loginLogId;
} public void setUserId(int userId) {
this.userId = userId;
} public void setIp(String ip) {
this.ip = ip;
} public void setLoginDate(Date loginDate) {
this.loginDate = loginDate;
}
}

LoginLog.java

 package com.smart.dao;

 import com.smart.domain.User;
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 java.sql.ResultSet;
import java.sql.SQLException; /**
* Created by sanglp on 2016/6/29.
*/
//通过Spring注解定义一个DAO
@Repository
public class UserDao {
//自动注入JdbcTemplate的Bean
@Autowired
private JdbcTemplate jdbcTemplate;
//根据用户名和密码获取匹配的用户数。等于1表示用户名/密码正确,等于0表示用户名或密码错误
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});
} /**
* 通过调用RowCallbackHandler回调接口实例,将ResultSet转换为User对象
* @param userName
* @return
*/
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() { //匿名类方式实现的回调函数
//processRow负责将查询的结果congenialResultSet装载到类似于领域对象的对象示例中
public void processRow(ResultSet resultSet) throws SQLException {
user.setUserId(resultSet.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()});
} }

UserDao.java

 package com.smart.dao;

 import com.smart.domain.LoginLog;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository; import java.io.Serializable; /**
* Created by sanglp on 2016/6/29.
*/
@Repository
public class LoginLogDao implements Serializable{
@Autowired
private JdbcTemplate jdbcTemplate; public void insertLoginLog(LoginLog loginLog){
String sqlStr="INSERT INTO t_login_log(user_id,ip,login_datetime) VALUES(?,?,?)";
jdbcTemplate.update(sqlStr,new Object[]{loginLog.getUserId(),loginLog.getIp(),loginLog.getLoginDate()});
}
}

LoginLogDao.java

 在UserDao和LoginLogDao实现类中都没有打开/释放Connection的代码,那么DAO如何访问数据库?
答:样板式的操作都被JdbcTemplate给封装起来了,JdbcTemplate本身需要一个DateSource,这样他就可以根据需要congenialDataSource中获取或返回连接。
UserDao和LoginLogDao都提供了一个带@Autowried注解的JdbcTemplate变量。所以必须事先声明一个数据源,然后定义一个JdbcTemplate Bean,通过Spring的
容器上下文自动绑定机制进行Bean的注入。

在Spring中装载DAO

 <?xml version="1.0" encoding="utf-8" ?>
<!--引用Spring的多个Schema空间格式定义文件-->
<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的注入-->
<!--使用Spring的context:component-scan扫描指定类包下的所有类,这样在类中定义的Spring注解(@Repository和@Autowired等才能产生作用)-->
<context:component-scan base-package="com.smart.dao"/>
<!--扫描service类包,应用Spring的注解配置-->
<context:component-scan base-package="com.smart.service"/>
<!--定义一个使用DBCP实现的数据源-->
<!--使用Jakarta的DBCP开源数据源实现方案定义个一个数据源并设置驱动,端口用户名密码-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"
p:driverClassName="com.mysql.jdbc.Driver"
p:url="jdbc:mysql://localhost:3306/sampledb"
p:username="root"
p:password="123456"/> <!--定义JDBC模板Bean-->
<!--配置JdbcTemplate将上面声明的dataSource注入JdbcTemplate中,而这个JdbcTemplate将通过@Autowired自动注入LoginLogDao和UserDao的Bean中-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"
p:dataSource-ref="dataSource"/>
<!--配置事务管理器 定义了基于数据源的DataSourceTransactionManager事务管理器,该事务管理器负责声明式事务的管理,该管理器需要引用dataSource Bean-->
<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>

ApplicationContext.xml

 package com.smart.service;

 import com.smart.dao.LoginLogDao;
import com.smart.dao.UserDao;
import com.smart.domain.LoginLog;
import com.smart.domain.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; /**
* Created by sanglp on 2016/6/30.
*/ //通过@Service注解将UserService标注为一个服务层的Bean,
@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); }
}

UserService.java

 package com.smart.service;

 import com.smart.domain.User;
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 javax.jws.soap.SOAPBinding; import java.util.Date; import static org.testng.Assert.*;
/**
* Created by sanglp on 2016/6/30.
* Spring3.1的测试框架可以和TestNG整合,通过Spring提供的测试基类AbatractTestNGSpringContextTests,可以将Spring
* 容器和TestNG测试框架整合。@ContextConfiguration也是Spring提供的注解,它用于指定Spring的配置文件。
* 在测试类中可以使用Spring的@Autowired将Spring容器中的Bean注入测试类中。在测试方法前通过TestNG的@Test注解即可将方法标注为测试方法。
*/
//启动Spring容器
@ContextConfiguration(locations ={"/applicationContext.xml"})
//基于TestNG的Spring测试框架
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); } @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);
}
}

UserServiceTest.java

 <?xml version="1.0" encoding="utf-8" ?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<context-param>
<!--从类路径下加载spring配置文件,classpath关键字特指在类路径下加载-->
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<!--负责启动spring的容器的监听器,他将引用处的上下文参数获得spring配置文件地址-->
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<!--spring mvc的主控Servlet-->
<servlet>
<!--Spring mvc也拥有一个spring配置文件,配置文件的文件名和此处定义的servlet名有一个契约,即采用<servlet名>-servlet.xml 因为这里为viewspace所以/WEB-INF目录下必须有一个VIEWSPACE-SERVLET.XMLL-->
<servlet-name>viewspace</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>3</load-on-startup>
</servlet>
<!--spring mvc处理的URL-->
<servlet-mapping>
<servlet-name>viewspace</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
</web-app>

web.xml配置Spring MVC

 package com.smart.web;

 import com.smart.domain.User;
import com.smart.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date; /**
* Created by sanglp on 2016/7/5.
*/
/**
* Spring mvc的@Controller注解可以将任何一个POJO的类标注为Spring MVC的控制器,处理HTTP请求,当然标注 了@Controller的类首先会是一个Bean,所以可以使用@Autowired进行Bean的注入
* 一个控制器可以拥有多个对应不同HTTP请求路径的处理方法,通过@RequestMapping指定方法如何映射请求路径
* 请求的参数会根据参数默认契约自动绑定到响应方法的入参中,在loginCheck方法中请求参数会按名称匹配绑定到loginCommand的入参中。
* 请求响应犯法会返回一个ModelAndView或直接返回一个字符串,Spring MVC会解析之并转向目标响应页面。
* ModelAndView对象既包括了视图信息又包括偶了视图渲染所需要的模型数据信息。
*/
//标注为一个controller
@Controller
@RequestMapping(value="/admin")
public class LoginController { @Autowired
public UserService userService;
@RequestMapping(value = "/login.html") //负责处理login.html的请求
public String loginPage(){
return "login";
} /**
* 控制器根据登录处理结果分别返回ModelAndView("login","error","用户名或密码错误")和ModelAndView("main")ModelAndView的第一个参数带包视图的逻辑名
* 第二个和第三个参数分别为数据模型名称和数据模型对象,数据模型对象将以数据模型名称为参数名放置到request的属性中
* @param request
* @param loginCommand
* @return
*/
@RequestMapping(value = "/loginCheck.html")
public ModelAndView loginCheck(HttpServletRequest request,LoginCommand loginCommand){
boolean isValidUser = userService.hasMatchUser(loginCommand.getUserName(),loginCommand.getPassword()); if(!isValidUser){
return new ModelAndView("login","error","用户名或密码错误");
}else{
User user=userService.findUserByUserName(loginCommand.getUserName());
user.setLastIp(request.getRemoteAddr());
user.setLastVisit(new Date());
userService.loginSuccess(user);
request.getSession().setAttribute("user",user);
return new ModelAndView("main");
}
}
}

LoginController.java

 package com.smart.web;

 /**
* Created by sanglp on 2016/7/5.
*/
public class LoginCommand {
private String userName;
private String password; public String getUserName() {
return userName;
} public String getPassword() {
return password;
} public void setUserName(String userName) {
this.userName = userName;
} public void setPassword(String password) {
this.password = password;
}
}

LoginCommand.java

 <?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"
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">
<!--扫描相应的包,应用spring注解-->
<context:component-scan base-package="com.smart.web"/>
<bean id="defaultAnnotationHandlerMapping" class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
<bean id="annotationMethodHandlerAdapter" class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/> <!--配置视图解析器,将ModelAndView及字符串解析为具体的页眉 在这里我们使用了InternalResourceViewResolver的视图映射方式,他通过添加前后缀来进行解析-->
<!--Springmvc如何将视图逻辑名解析为具体的视图页眉呢? 通过prefix指定在视图名前所添加的前缀,通过suffix指定在视图名后添加的后缀-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:viewClass="org.springframework.web.servlet.view.JstlView"
p:prefix="/WEB-INF/jsp/"
p:suffix=".jsp"/>
</beans>

viewspace-servlet.xml

 <%@ page language="java" contentType="text/html" charset="UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<title>景区网站登录</title>
</head>
<body>
<c:if test="${!empty error}">
<!--使用JSTL标签对登录返回的信息进行错误处理,JSTL标签中引用了error变量,这个变量正是LoginController中返回的ModelAndView("login","error","用户名或密码错误")对象所声明的error参数-->
<font color="red"><c:out value="${error}"/></font>
</c:if>
<!--login.jsp登录表单提交到loginController.html JSTL标签会在URL前自动加上应用程序部署根目录,假设应用部署在网站的viewspace目录下,标签将输出/viewspace/loginController.html
由于login.jsp放在WEB-INF/jsp目录下,无法直接通过URL进行调用,他由LoginController控制类中标注了@RequestMapping(value="/login.html")的loginPage()进行转发-->
<form action="<c:url value="/loginCheck.html"/>" method="post">
用户名:
<input type="text" name="userName">
<br/>
密码:
<input type="password" name="password">
<br/>
<input type="submit" value="登录"/>
<input type="reset" value="重置"/>
</form>
</body>
</html>

login.jsp

 <%@ page language="java" contentType="text/html" charset="UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<title>景区后台管理主页面</title>
</head>
<body>
<!--访问Session域中的user对象,显示用户名和积分信息-->
${user.userName},欢迎您进入景区管理后台!
</body>
</html>

main.jsp

jetty无法启动使用:mvn org.mertbay.jetty:maven-jetty-plugin:run

Spring学习进阶(一)初识Spring