最近学习SSH框架,看到Spring部分,下面通过实现一个登陆Demo来学习Spring的工作流程,配置,注解的使用等知识点。
1、在Eclipse下新建名为SpringDemo的Dynamic Web Project项目,导入spring相关jar包到lib目录下。
此外,项目还需导入aopallince、commons-logging、commons-dbcp、commons-collections、commons-pool等依赖jar包;
jsp页面使用了JSTL,因此需要在原lib基础上增加jstl.jar和standard.jar;数据库链接需mysql-connector-java包。
有时还需根据控制台的出错异常信息,导入缺少的jar包。
2、在web.xml下对Spring进行相关配置。
web.xml内容如下:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>SpringDemo</display-name> <context-param> <param-name>webAppRootKey</param-name> <param-value>SpringDemo.webapp.root</param-value> </context-param> <!-- 指定log4j配置文件的位置 --> <!-- WebApplicationContext需要使用日志功能,放在Spring配置的前面 --> <context-param> <param-name>log4jConfigLocation</param-name> <param-value>classpath:log4j.xml</param-value> </context-param> <!-- --> <context-param> <param-name>log4fRefreshInterval</param-name> <param-value>60000</param-value> </context-param> <!-- 指定Spring配置文件 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/applicationContext.xml</param-value> </context-param> <!-- 定义Web容器监听器,监听器负责完成IoC容器在Web环境中的启动工作 --> <!-- IoC容器启动过程就是建立上下文的过程 --> <!-- ContextLoaderListener启动的上下文为根上下文 --> <!-- ContextLoaderListener实现了ServletContextListener接口 --> <!-- ContextLoaderListener->ContextLoader:1,载入IoC容器到Web容器;2,实例化WebApplicationContext --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 配置log4j的监听器 --> <listener> <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class> </listener> <!-- DispatcherServlet起着分发请求的作用,Spring MVC的核心 --> <!-- ContextLoaderListener初始化完成后,Web容器开始初始化DispatcherServlet --> <servlet> <servlet-name>spring</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/dispatcherServlet.xml</param-value> </init-param> </servlet> <!-- 指定需要处理的http请求 --> <servlet-mapping> <servlet-name>spring</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>3、在applicationContext.xml中配置Spring注解、数据库等信息
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- 启动包扫描功能,将带有@Controller、@Service、@repository、@Component等注解的类 自动转化为成为spring的bean --> <context:component-scan base-package="com.demo.service" /> <context:component-scan base-package="com.demo.dao" /> <!-- 数据源配置的文件,引入spring容器 --> <context:property-placeholder location="classpath:database.properties" /> <!-- dataSource,配置构建基于DBCP的数据源 --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" lazy-init="false" p:driverClassName="${dataSource.driverClassName}" p:url="${dataSource.url}" p:username="${dataSource.username}" p:password="${dataSource.password}" p:maxActive="${dataSource.maxActive}" p:maxIdle="${dataSource.maxIdle}" p:maxWait="${dataSource.maxWait}" /> <!-- 定义jdbcTemplate模版的Bean--> <bean class="org.springframework.jdbc.core.JdbcTemplate"<pre name="code" class="html">p:dataSource-ref="dataSource" /> <!-- 事务管理配置 --> <beanid="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"p:dataSource-ref="dataSource" /><tx:annotation-driventransaction-manager="transactionManager" /> </beans>
其中引用的database.properties文件内容如下:
dataSource.driverClassName=com.mysql.jdbc.Driver dataSource.url=jdbc:mysql://localhost:3306/User dataSource.username=root dataSource.password=123456 dataSource.maxActive=200 dataSource.maxIdle=50 dataSource.maxWait=100004、在dispatcherServlet.xml中,配置控制层、AOP、视图解析等信息。
<?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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="com.demo.controller" /> <bean id="urlMapping" class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" /> <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" /> <!-- 对模型视图名称的解析,在请求时模型视图名称添加前后缀,将ModelAndView解析为具体页面 --> <!-- 使用了JstlView作为视图解析器。同时,指定前缀路径为"/WEB-INF/jsp/",后缀路径为".jsp Spring容器将会在这个路径中寻找匹配的jsp文件! --> <bean id="jstlViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:prefix="/WEB-INF/views/" p:suffix=".jsp" /> </beans>
“org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter”直接关系到多动作控制器配置是否可用!必须配置正确
5、新建Account实体类
package com.demo.domain; import java.io.Serializable; public class Account implements Serializable { /** * */ private static final long serialVersionUID = 1862537539462186097L; private Integer id; private String username; private String password; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } 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; } public Account(){} }6、新建AccountDAO接口
package com.demo.dao; import com.demo.domain.Account; public interface AccountDao { int getMatchCount(String username, String password); Account getAcoountById(int id); Account getAccountByName(String username); }7、新建AccountDaoImpl实现AccountDao接口,并配置@Repository注解,@Autowired注入jdbcTemplate用来访问数据库。
package com.demo.dao.impl; 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.demo.dao.AccountDao; import com.demo.domain.Account; @Repository public class AccountDaoImpl implements AccountDao { @Autowired private JdbcTemplate jdbcTemplate; @Override public int getMatchCount(String username, String password) { String strSql = "select count(*) from user " + " where name = ? and password = ?";//?为参数占位符 return jdbcTemplate.queryForInt(strSql, new Object[]{ username, password}); } @Override public Account getAcoountById(int id) { String strSql = "select id,name from user " + " where id = ?"; System.out.println("##########execute sql: "+strSql); final Account account = new Account(); jdbcTemplate.query(strSql, new Object[]{ id }, //匿名方式实现的回调函数 new RowCallbackHandler(){ @Override public void processRow(ResultSet rs) throws SQLException { //将查询结果封装到对象实例中 account.setId(rs.getInt("id")); account.setUsername(rs.getString("name")); } }); return account; } @Override public Account getAccountByName(String username) { String strSql = "select id,name from user " + " where name = ?"; System.out.println("##########execute sql: "+strSql); final Account account = new Account(); jdbcTemplate.query(strSql, new Object[]{ username }, //匿名方式实现的回调函数 new RowCallbackHandler(){ @Override public void processRow(ResultSet rs) throws SQLException { //将查询结果封装到对象实例中 account.setId(rs.getInt("id")); account.setUsername(rs.getString("name")); } }); return account; } }8、新建AccountService接口。
package com.demo.service; import com.demo.domain.Account; public interface AccountService { boolean hasMatchAccount(String username, String password); Account getAccountById(int id); Account getAccountByName(String username); }9、新建AccountServiceImpl类实现AccountService接口,并配置@Service注解,@Autowried注入AccountDao用来访问DAO
package com.demo.service.impl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.demo.dao.AccountDao; import com.demo.domain.Account; import com.demo.service.AccountService; @Service public class AccountServiceImpl implements AccountService{ @Autowired private AccountDao accountDao; @Override public boolean hasMatchAccount(String username, String password) { return accountDao.getMatchCount(username, password)>0; } @Override public Account getAccountById(int id) { return accountDao.getAcoountById(id); } @Override public Account getAccountByName(String username) { return accountDao.getAccountByName(username); } }10、新建LoginController类,并配置@Controller注解,@Autowired注入AccountService;用来响应login请求。
package com.demo.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import com.demo.domain.Account; import com.demo.service.AccountService; @Controller public class LoginController { @Autowired private AccountService accountService; /** * init login form * @param model * @return */ @RequestMapping(value="/login.do", method = RequestMethod.GET) public String initForm(ModelMap model){ System.out.println("########## init login page."); Account account = new Account(); //绑定账户对象,也就是这个登录表单对象 model.addAttribute("account", account); //指向登录页面 return "login"; } /** * login check * @param user * @return */ @RequestMapping(value="/loginCheck.do",method = RequestMethod.POST) public String login(@ModelAttribute("user") Account account) { Account account2 = accountService.getAccountByName(account.getUsername()); if (account2 != null) { return "redirect:profile.do?id=" + account2.getId(); } else { return "redirect:login.do"; } } }11、新建AccountController类,并配置@Controller注解,@Autowired注入AccountService;用来响应profile请求。
package com.demo.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import com.demo.domain.Account; import com.demo.service.AccountService; @Controller public class AccountController { @Autowired private AccountService accountService; /** * * @param id * @param model * @return */ @RequestMapping(value="/profile.do",method = RequestMethod.GET) public String proflie(@RequestParam("id") int id, ModelMap model){ Account account = accountService.getAccountById(id); model.addAttribute("account", account); //跳转到用户信息界面 return "profile"; } }12、以上接口和类的结构图如下:
在上面的类中,都是用注解来进行配置。注解的确减少了代码的开发量,提高了效率。当然,这对于我们理解程序是一种挑战!如果你不知道原有的SpringMVC的流程,很难一开始就能摆弄清楚这些内容!
13、在WEB-INF目录下新建views文件夹,建立需要的jsp页面。
login.jsp内容如下:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ include file="/WEB-INF/views/taglib.jsp"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Login Page</title> </head> <body> <fieldset><legend>登录</legend> <form:form commandName="account" action="loginCheck.do" method="post"> <ul> <li><form:label path="username">用户名:</form:label><form:input path="username" /></li> <li><form:label path="password">密码:</form:label><form:password path="password" /></li> <li> <button type="submit">登录</button> <button type="reset">重置</button> </li> </ul> </form:form> </fieldset> </body> </html>profile.jsp内容如下:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Profile Page</title> </head> <body> <fieldset><legend>用户信息</legend> <ul> <li><label>用户名:</label><c:out value="${account.username}" /></li> </ul> </fieldset> </body> </html>taglib.jsp内容如下:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%> <%@ taglib prefix="sql" uri="http://java.sun.com/jsp/jstl/sql"%> <%@ taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml"%> <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%> <%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>14、WEB-INF目录内容结构图如下:
15、整个项目Demo的编码工作基本就是这样。运行效果如下图:
登陆界面
用户信息界面:
16、总结:通过实现一个登陆Demo,学习了一下Spring框架的基本使用,项目比较简单,因此还有很多知识点未能涉及到。
Spring作为一个非常优秀的框架,可以号称“全栈框架”。
但是,从代码中依然可以看到Spring框架的不足。DAO层的数据库操作代码比较繁琐,而这里就有了ORM框架的用武之地。
Hibernate甚至连sql都不用写,就可实现常见的增删查改操作。
Spring作为一个开放性框架,能非常便捷的整合ORM框架。
原文地址:http://blog.csdn.net/dutsoft/article/details/41545091