近来无事,复习复习Spring相关知识,从《Spring企业应用开发实战》这本书开始。
本文为学习《Spring企业应用开发实战》总结,著作权归原作者。
一、用Maven建立web项目
1.点击“File”->“New”->"Other"->输入“Maven”,新建一个“Maven Project”,如下图所示:

2.请勾选“Create a simple project”,创建一个简单的项目,不使用模板。也可以使用模板,选择WebApp,不过这里就不应该勾选。如下图所示:

3.填写好包名、项目名,选择打包类型为:war,如下图所示:

4.项目创建好后可能会发现有错误,选择项目,右键“属性properties”->"层面Project Facets"->"Java"修改版本号为1.8,默认为1.5;点击“Ok”保存后关闭。如下图所示:

5.重复上一个步骤,反勾Dynamic Web Module,将项目暂时变成非Web项目。点击“Ok”保存后关闭。

6.重复上一步骤,再进层面属性,勾选“Dynamic Web Module”选择Version为3.0。点击左下角的超链接“Further Configuration available...“。

7.勾选“Generate web.xml deployment descriptor”生成web.xml部署描述文件。点击“Ok”保存后关闭。

8.将生成的WebContent目录下的两个文件夹“META-INF”与“WEB-INF”复制到src/main/webapp目录下。

9.删除WebContent目录。

10.删除后会发现项目的pom.xml文件报错,是因为找不到指定位置的web.xml文件引起的。再进入项目的属性,选择“Deployment Assembly”项目部署项,删除“src/test/java”、“src/test/resources”与“WebContent”目录,因为这三项不需要部署出去。

11.点击“Add添加”后选择“Folder文件夹”为项目的最终部署结果指定Web内容根文件夹。

12.选择src\main\webapp目录为目标目录,点击“Finish完成”保存并关闭。

13.如果此时项目还报错,随便修改pom.xml文件后保存后应该错误会消失。
14.此后项目运行需要添加tomcat运行环境就不赘述了。
二、类包规划,添加依赖,数据库准备
1.类包规划

2.pom.xml中添加lib依赖
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/xsd/maven-4.0.0.xsd">
3 <modelVersion>4.0.0</modelVersion>
4 <groupId>com.adam</groupId>
5 <artifactId>Chapter2</artifactId>
6 <version>0.0.1-SNAPSHOT</version>
7 <packaging>war</packaging>
8 <properties>
9 <!-- springframe 版本控制 -->
10 <spring.version>4.1.1.RELEASE</spring.version>
11 </properties>
12
13 <dependencies>
14 <!-- springframe start -->
15 <dependency>
16 <groupId>org.springframework</groupId>
17 <artifactId>spring-core</artifactId>
18 <version>${spring.version}</version>
19 </dependency>
20
21 <dependency>
22 <groupId>org.springframework</groupId>
23 <artifactId>spring-web</artifactId>
24 <version>${spring.version}</version>
25 </dependency>
26
27 <dependency>
28 <groupId>org.springframework</groupId>
29 <artifactId>spring-oxm</artifactId>
30 <version>${spring.version}</version>
31 </dependency>
32
33 <dependency>
34 <groupId>org.springframework</groupId>
35 <artifactId>spring-tx</artifactId>
36 <version>${spring.version}</version>
37 </dependency>
38
39 <dependency>
40 <groupId>org.springframework</groupId>
41 <artifactId>spring-jdbc</artifactId>
42 <version>${spring.version}</version>
43 </dependency>
44
45 <dependency>
46 <groupId>org.springframework</groupId>
47 <artifactId>spring-webmvc</artifactId>
48 <version>${spring.version}</version>
49 </dependency>
50
51 <dependency>
52 <groupId>org.springframework</groupId>
53 <artifactId>spring-aop</artifactId>
54 <version>${spring.version}</version>
55 </dependency>
56
57 <dependency>
58 <groupId>org.springframework</groupId>
59 <artifactId>spring-context-support</artifactId>
60 <version>${spring.version}</version>
61 </dependency>
62
63 <dependency>
64 <groupId>org.springframework</groupId>
65 <artifactId>spring-test</artifactId>
66 <version>${spring.version}</version>
67 </dependency>
68 <!-- springframe end -->
69
70 <!--mysql数据库驱动 -->
71 <dependency>
72 <groupId>mysql</groupId>
73 <artifactId>mysql-connector-java</artifactId>
74 <version>5.1.38</version>
75 </dependency>
76 <!--log4j日志包 -->
77 <dependency>
78 <groupId>org.apache.logging.log4j</groupId>
79 <artifactId>log4j-core</artifactId>
80 <version>2.6.1</version>
81 </dependency>
82 <!-- JUnit单元测试工具 -->
83 <dependency>
84 <groupId>junit</groupId>
85 <artifactId>junit</artifactId>
86 <version>4.10</version>
87 </dependency>
88 <!-- aspectJ AOP 织入器 -->
89 <dependency>
90 <groupId>org.aspectj</groupId>
91 <artifactId>aspectjweaver</artifactId>
92 <version>1.8.9</version>
93 </dependency>
94 <!-- jstl -->
95 <dependency>
96 <groupId>javax.servlet</groupId>
97 <artifactId>jstl</artifactId>
98 <version>1.2</version>
99 </dependency>
100 </dependencies>
101
102 <build>
103 <plugins>
104 <!-- define the project compile level -->
105 <plugin>
106 <groupId>org.apache.maven.plugins</groupId>
107 <artifactId>maven-compiler-plugin</artifactId>
108 <version>2.3.2</version>
109 <configuration>
110 <source>1.8</source>
111 <target>1.8</target>
112 </configuration>
113 </plugin>
114 </plugins>
115 </build>
116 </project>
如果eclise没有自动下载jar包,右键“属性properties”->"Maven"->"Update Project..",强制更新。
3.数据库准备
建立数据库sampledb,添加两张表,结构如下:


t_user为用户信息表,t_login_log为用户登录日志表。表的引擎要指定InnoDB,因为该引擎支持事务。

初始化一条数据,用户名和密码用于测试登录。
三、持久层
1.建立领域对象(实体类)
User.java
1 package com.adam.domain;
2
3 import java.io.Serializable;
4 import java.util.Date;
5
6 public class User implements Serializable {
7 private int userId;
8 private String userName;
9 private String password;
10 private int credits;
11 private String lastIp;
12 private Date lastVisit;
13
14 public int getUserId() {
15 return userId;
16 }
17
18 public void setUserId(int userId) {
19 this.userId = userId;
20 }
21
22 public String getUserName() {
23 return userName;
24 }
25
26 public void setUserName(String userName) {
27 this.userName = userName;
28 }
29
30 public String getPassword() {
31 return password;
32 }
33
34 public void setPassword(String password) {
35 this.password = password;
36 }
37
38 public int getCredits() {
39 return credits;
40 }
41
42 public void setCredits(int credits) {
43 this.credits = credits;
44 }
45
46 public String getLastIp() {
47 return lastIp;
48 }
49
50 public void setLastIp(String lastIp) {
51 this.lastIp = lastIp;
52 }
53
54 public Date getLastVisit() {
55 return lastVisit;
56 }
57
58 public void setLastVisit(Date lastVisit) {
59 this.lastVisit = lastVisit;
60 }
61
62 }
LoginLog.java
1 package com.adam.domain;
2
3 import java.io.Serializable;
4 import java.util.Date;
5
6 public class LoginLog implements Serializable {
7 private int loginLogId;
8 private int userId;
9 private String ip;
10 private Date loginDate;
11
12 public int getLoginLogId() {
13 return loginLogId;
14 }
15
16 public void setLoginLogId(int loginLogId) {
17 this.loginLogId = loginLogId;
18 }
19
20 public int getUserId() {
21 return userId;
22 }
23
24 public void setUserId(int userId) {
25 this.userId = userId;
26 }
27
28 public String getIp() {
29 return ip;
30 }
31
32 public void setIp(String ip) {
33 this.ip = ip;
34 }
35
36 public Date getLoginDate() {
37 return loginDate;
38 }
39
40 public void setLoginDate(Date loginDate) {
41 this.loginDate = loginDate;
42 }
43
44 }
2.数据处理对象
UserDao.java
1 package com.adam.dao;
2
3 import java.sql.ResultSet;
4 import java.sql.SQLException;
5
6 import org.springframework.beans.factory.annotation.Autowired;
7 import org.springframework.jdbc.core.JdbcTemplate;
8 import org.springframework.jdbc.core.RowCallbackHandler;
9 import org.springframework.stereotype.Repository;
10
11 import com.adam.domain.User;
12
13 @Repository
14 public class UserDao {
15 @Autowired
16 private JdbcTemplate jdbcTemplate;
17
18 public int getMatchCount(String name, String password) {
19 String sql = "SELECT count(*) FROM t_user WHERE user_name = ? and password = ?";
20 return jdbcTemplate.queryForInt(sql, new Object[] { name, password });
21 }
22
23 public User findUserByName(final String name) {
24 String sql = "select user_id,user_name,credits from t_user where user_name = ?";
25 final User user = new User();
26 jdbcTemplate.query(sql, new Object[] { name }, new RowCallbackHandler() {
27
28 public void processRow(ResultSet rs) throws SQLException {
29 user.setUserId(rs.getInt("user_id"));
30 user.setUserName(name);
31 user.setCredits(rs.getInt("credits"));
32 }
33 });
34 return user;
35 }
36
37 public void updateLoginInfo(User user) {
38 String sql = "update t_user set last_visit = ?,last_ip = ?, credits = ? where user_id = ?";
39 jdbcTemplate.update(sql,
40 new Object[] { user.getLastVisit(), user.getLastIp(), user.getCredits(), user.getUserId() });
41 }
42 }
LoginLogDao.java
1 package com.adam.dao;
2
3 import org.springframework.beans.factory.annotation.Autowired;
4 import org.springframework.jdbc.core.JdbcTemplate;
5 import org.springframework.stereotype.Repository;
6
7 import com.adam.domain.LoginLog;
8
9 @Repository
10 public class LoginLogDao {
11 @Autowired
12 private JdbcTemplate jdbcTemplate;
13
14 public void insertLoginLog(LoginLog loginLog) {
15 String sql = "insert into t_login_log(user_id, ip,login_datatime) values(?,?,?)";
16 Object[] pra = { loginLog.getUserId(), loginLog.getIp(), loginLog.getLoginDate() };
17 jdbcTemplate.update(sql, pra);
18 }
19 }
3.在spring中装配Dao
在Dao中并没有打开或释放数据库连接,那么Dao是如何访问数据库的?而且在Dao中使用的JdbcTemplate是从哪来的?这都是spring帮我们实现的,所以需要在spring中装配Dao。
创建spring配置文件applicationContext.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" xmlns:p="http://www.springframework.org/schema/p" 4 xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" 5 xmlns:tx="http://www.springframework.org/schema/tx" 6 xsi:schemaLocation="http://www.springframework.org/schema/beans 7 http://www.springframework.org/schema/beans/spring-beans.xsd 8 http://www.springframework.org/schema/context 9 http://www.springframework.org/schema/context/spring-context-4.3.xsd 10 http://www.springframework.org/schema/aop 11 http://www.springframework.org/schema/aop/spring-aop-4.3.xsd 12 http://www.springframework.org/schema/tx 13 http://www.springframework.org/schema/tx/spring-tx.xsd"> 14 ... 15 </beans>
在其中加入配置信息
1 <!-- 扫描包,应用注解 --> 2 <context:component-scan base-package="com.adam.dao" /> 3 <!--定义一个jdbc数据源,创建一个驱动管理数据源的bean --> 4 <bean id="jdbcDataSource" 5 class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 6 <property name="driverClassName" value="com.mysql.jdbc.Driver" /> 7 <property name="url" value="jdbc:mysql://localhost:3306/sampledb" /> 8 <property name="username" value="root" /> 9 <property name="password" value="AdamJin" /> 10 </bean> 11 <!-- 定义jdbc模板Bean --> 12 <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" 13 p:dataSource-ref="jdbcDataSource" />
四、业务层
1.建立业务处理类
UserService.java
1 package com.adam.service;
2
3 import org.springframework.beans.factory.annotation.Autowired;
4 import org.springframework.stereotype.Service;
5
6 import com.adam.dao.LoginLogDao;
7 import com.adam.dao.UserDao;
8 import com.adam.domain.LoginLog;
9 import com.adam.domain.User;
10
11 @Service
12 public class UserService {
13 @Autowired
14 private UserDao userdao;
15 @Autowired
16 private LoginLogDao loginLogDao;
17
18 public boolean hasMatchUser(String name, String password) {
19 int matchCount = userdao.getMatchCount(name, password);
20 return matchCount > 0;
21 }
22
23 public User findUserByUsername(String username) {
24 return userdao.findUserByName(username);
25 }
26
27 public void loginSuccess(User user) {
28 user.setCredits(user.getCredits() + 5);
29 LoginLog loginLog = new LoginLog();
30 loginLog.setUserId(user.getUserId());
31 loginLog.setIp(user.getLastIp());
32 loginLog.setLoginDate(user.getLastVisit());
33 userdao.updateLoginInfo(user);
34 loginLogDao.insertLoginLog(loginLog);
35 }
36 }
2.在spring中装配Service
打开刚建立的applicationContext.xml,在其中添加
1 <!-- 扫描包,应用注解 --> 2 <context:component-scan base-package="com.adam.service" /> 3 <!-- 配置事务管理器 --> 4 <bean id="transactionManager" 5 class="org.springframework.jdbc.datasource.DataSourceTransactionManager" 6 p:dataSource-ref="jdbcDataSource" /> 7 8 <!-- 通过AOP配置事务增强,让service包下所有Bean的所有方法拥有事务 --> 9 <aop:config proxy-target-class="true"> 10 <aop:pointcut expression="execution(* com.adam.service..*(..))" 11 id="serviceMethod" /> 12 <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethod" /> 13 </aop:config> 14 <tx:advice id="txAdvice" transaction-manager="transactionManager"> 15 <tx:attributes> 16 <tx:method name="*"></tx:method> 17 </tx:attributes> 18 </tx:advice>
至此后端就算完成了,可以进行单元测试了。
五、单元测试
右击New->Other选择如图,创建单元测试类

TestUserService.java
1 package com.adam.test;
2 import static org.junit.Assert.*;
3
4 import java.util.Date;
5
6 import org.junit.Test;
7 import org.junit.runner.RunWith;
8 import org.springframework.beans.factory.annotation.Autowired;
9 import org.springframework.test.context.ContextConfiguration;
10 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
11
12 import com.adam.domain.User;
13 import com.adam.service.UserService;
14
15 @RunWith(SpringJUnit4ClassRunner.class)
16 @ContextConfiguration(locations = { "/applicationContext.xml" })
17 public class TestUserService {
18 @Autowired
19 private UserService userService;
20
21 @Test
22 public void hasMatchedUser() {
23 boolean b1 = userService.hasMatchUser("admin", "123456");
24 boolean b2 = userService.hasMatchUser("admin", "1236");
25
26 assertTrue(b1);
27 assertTrue(!b2);
28 }
29
30 @Test
31 public void findUserByUsername(){
32 User user = userService.findUserByUsername("admin");
33 assertEquals(user.getUserName(), "admin");
34 user.setLastIp("192.168.11.188");
35 user.setLastVisit(new Date());
36 userService.loginSuccess(user);
37 }
38
39 }
Run As -> JUnit Test得到以下结果,便测试成功,数据库也会多出登陆日志数据。

六、展示层
业务层和持久层开发任务结束,需要界面提供展示。
1.配置Spring MVC框架
修改web.xml文件
1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xmlns="http://java.sun.com/xml/ns/javaee" 4 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" 5 id="WebApp_ID" version="3.0"> 6 <!-- 从类路径下载spring配置文件 --> 7 <context-param> 8 <param-name>contextConfigLocation</param-name> 9 <param-value> 10 classpath:applicationContext.xml 11 </param-value> 12 </context-param> 13 <!-- 负责启动spring容器监听器,将引用上面的上下文参数获取spring配置文件地址 --> 14 <listener> 15 <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 16 </listener> 17 <!-- springMVC主控制servlet --> 18 <servlet> 19 <servlet-name>adam</servlet-name> 20 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 21 <init-param> 22 <param-name>contextConfigLocation</param-name> 23 <param-value>classpath:adam-servlet.xml</param-value> 24 </init-param> 25 <load-on-startup>2</load-on-startup> 26 </servlet> 27 <!-- springMVC处理的url --> 28 <servlet-mapping> 29 <servlet-name>adam</servlet-name> 30 <url-pattern>*.html</url-pattern> 31 </servlet-mapping> 32 </web-app>
注意:上面代码23行若不配置,spring会到WEB-INF下找*-servle.xml,*是servlet配置的name。
adam-servlet.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" xmlns:p="http://www.springframework.org/schema/p" 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 <!-- 扫描包,应用注解 --> 11 <context:component-scan base-package="com.adam.web" /> 12 13 <!-- 配置视图解析器 --> 14 <bean 15 class="org.springframework.web.servlet.view.InternalResourceViewResolver" 16 p:viewClass="org.springframework.web.servlet.view.JstlView" p:prefix="/WEB-INF/jsp/" 17 p:suffix=".jsp" /> 18 19 </beans>
2.控制器类
LoginController.java
1 package com.adam.web;
2
3 import java.util.Date;
4
5 import javax.servlet.http.HttpServletRequest;
6
7 import org.springframework.beans.factory.annotation.Autowired;
8 import org.springframework.stereotype.Controller;
9 import org.springframework.web.bind.annotation.RequestMapping;
10 import org.springframework.web.servlet.ModelAndView;
11
12 import com.adam.domain.User;
13 import com.adam.service.UserService;
14
15 @Controller
16 public class LoginController {
17 @Autowired
18 private UserService userService;
19
20 @RequestMapping(value = "/index.html")
21 public String loginPage() {
22 return "login";
23 }
24
25 @RequestMapping(value = "/loginCheck.html")
26 public ModelAndView loginCheck(HttpServletRequest request, LoginCommand loginCommand){
27 boolean isVaildUser = userService.hasMatchUser(loginCommand.getUsername(), loginCommand.getPassword());
28 if(!isVaildUser){
29 return new ModelAndView("login", "error", "用户名或密码错误");
30 }else{
31 User user = userService.findUserByUsername(loginCommand.getUsername());
32 user.setLastIp(request.getLocalAddr());
33 user.setLastVisit(new Date());
34 userService.loginSuccess(user);
35 request.getSession().setAttribute("user", user);
36 return new ModelAndView("main");
37 }
38 }
39 }
其中需要一个表单pojo
LoginCommand.java
1 package com.adam.web;
2
3 public class LoginCommand {
4 private String username;
5 private String password;
6
7 public String getUsername() {
8 return username;
9 }
10
11 public void setUsername(String username) {
12 this.username = username;
13 }
14
15 public String getPassword() {
16 return password;
17 }
18
19 public void setPassword(String password) {
20 this.password = password;
21 }
22
23 }
3.jsp视图页面
在WEB-INF下建立文件夹jsp,并新建以下文件。
login.jsp
1 <%@ page language="java" contentType="text/html; charset=UTF-8"
2 pageEncoding="UTF-8"%>
3 <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
4 <html>
5 <head>
6 <title>登陆</title>
7 </head>
8 <body>
9 <c:if test="${!empty error}">
10 <font color="red"><c:out value="${error}" /></font>
11 </c:if>
12 <form action="<c:url value="/loginCheck.html"/>" method="post">
13 用户名: <input type="text" name="username"> <br /> 密 码: <input
14 type="password" name="password"> <br /> <input type="submit"
15 value="提交"> <input type="reset" value="重置">
16 </form>
17 </body>
18 </html>
main.jsp
1 <%@ page language="java" contentType="text/html; charset=UTF-8"
2 pageEncoding="UTF-8"%>
3 <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
4 <html>
5 <head>
6 <title>首页</title>
7 </head>
8 <body>${user.userName},欢迎您,您的积分是${user.credits}。
9 </body>
10 </html>
到此,整个实例就完成了。
七、运行
Run As -> Run on Server,输入地址 http://localhost:8080/Chapter2/index.html 便会看到

输入正确的信息即可登录成功


