tonglin0325的个人主页

Spring MVC学习笔记——完整的用户登录

1.搭建环境的第一步是导包,把下面这些包都导入工程中

/media/common/工作/Ubuntu软件/SpringMVC_jar包整理/aop
/media/common/工作/Ubuntu软件/SpringMVC_jar包整理/apache-commons-logging
/media/common/工作/Ubuntu软件/SpringMVC_jar包整理/apache-log4j
/media/common/工作/Ubuntu软件/SpringMVC_jar包整理/bean-validator
/media/common/工作/Ubuntu软件/SpringMVC_jar包整理/dbcp
/media/common/工作/Ubuntu软件/SpringMVC_jar包整理/hibernate-3.6.8.
/media/common/工作/Ubuntu软件/SpringMVC_jar包整理/JSTL
/media/common/工作/Ubuntu软件/SpringMVC_jar包整理/mysql
/media/common/工作/Ubuntu软件/SpringMVC_jar包整理/pager
/media/common/工作/Ubuntu软件/SpringMVC_jar包整理/sitemesh
/media/common/工作/Ubuntu软件/SpringMVC_jar包整理/spring

手动导包也可以,不过不是很方便,推荐学习使用maven的pom.xml文件来导入jar包

整个系统的结构

表示层(JSP页面),一般包名是view

** 
   ▼**

控制层,一般包名是action或者web,控制层也会操作实体层

**  ▼**

业务逻辑层,一般包名是service

**  ▼**

数据持久层,一般包名是dao

**  ▼**

实体层(JavaBean),一般包名是model或者entity

 

写成的过程和上面的方向相反,从下往上写

实体Entity层

**  1.先写User类**

**    Id,username,nickname,password,email**

**    其中还包括注入**

**  2.再写Page类**

**    public class Pager**

**    List datas、offset、size、total**

**  3.写SystemContext类**

**  7.写UserException异常类**

 

数据持久层dao层,主要是操作Hibernate,还要写beans.xml

**  4.写IUserDao接口**

**    增、更新、删除、根据ID查用户load、查所用用户List list、查分页Pager find、根据username查用户loadByUsername**

**  5.实现IUserDao接口**

**    分页find()中取得SystemContext类**

 

业务逻辑层service层,主要是写验证

**  6.写IUserService接口**

**    增、更新、删除、根据ID查用户load、查所用用户List list、查分页Pager find、根据username查用户loadByUsername**

**  8.实现IUserService接口**

    密码登录验证login、添加用户、修改用户、删除用户、查询用户、列出所有用户、分页find()

 

控制层action层

  9.LoginFilter.java登录权限,实现Filter接口,doFilter()方法

**    在请求是/user/的时候拦截验证权限,没有权限重定向/login,有权限放行*

  10.SystemContext.java分页过滤,实现Filter接口,doFilter()方法

 

**    在请求是/中,如果参数为Pager.offset的时候,拦截取得offset,设置SystemContext中的offset和size*

  11.IndexController.java,Session共享数据

    在请求是/login的时候,将ModelMap中的属性放入Session中,实现多窗口共享数据

  12.UserController.java,总的请求为/user,这也就是MVC模型中的RequestMapping

    在请求是/user和/的时候,向model模型中添加——userService.find()

    在请求是/add的时候(分GET和POST),向model模型中添加——new User()

    在请求是/{id}的时候,向model模型中添加——userService.load(id)

    在请求是/{id}/update的时候**(分GET和POST)**

    在请求是/{id}/delete的时候…

 

    最后再传给DispatchServlet,使用model从Controller给视图传值

    在jsp中通过 ${ } 取得属性

    记得加上@Controller,通过Annotation来配置控制器

 

注意:在持久层、业务层、控制层中,分别采用@Repository、@Service、@Controller对分层中的类进行注释

 

 

 

2.在工程的src/目录下加入beans.xml、jdbc.properties和log4j.properties这三个文件

 

3.新建一个数据库文件

  新建一个数据库spring_user

1
2
mysql> create database spring_user;

 

  并把字符编码改成UTF-8,可以参考 Ubuntu下的MySQL安装

1
2
create database spring_user default character set utf8 collate utf8_general_ci;

   添加t_user表

1
2
CREATE TABLE IF NOT EXISTS `t_user` (`username` varchar(64) NOT NULL,`password` varchar(11) NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8;

 

**  插入用户和密码**

1
2
INSERT INTO t_user (username,password) VALUES('admin','admin');

 4.接下来在页面就可以用admin来登录

**  而且中文也正常显示**

 

 

整个项目的结构

**  1.JSP页面:登录、添加、列表、详情、更新、错误**

**  2.实体层(Bean或者model):分页类、分页查询结果类、用户类、Exception类**

**  3.控制层(Action):页面控制器、登录过滤器、分页查询结果过滤器、用户控制器**

**  4.业务逻辑层(Service):一个接口和一个实现类(包括注入userDAO、登入验证、添删该查用户等等)**

**  5.数据持久层(DAO):**一个接口和一个实现类(和HibernateDaoSupport相关,用户增删改查等等)

 

 

1.JSP页面

  login.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!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>用户登录</title>
</head>
<body>
<form method="post">
用户名:<input type="text" name="username"/><br/>
用户密码:<input type="password" name="password"/><br/>
<input type="submit" value="用户登录"/>
</form>
</body>
</html>

 

  error.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!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>发现异常</title>
</head>
<body>
<h1>${exception.message }</h1>
</body>
</html>

** **

** add.jsp**

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="sf" uri="http://www.springframework.org/tags/form" %>
<!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>用户添加</title>
</head>
<body>
<sf:form method="post" modelAttribute="user">
<table width="700" align="center" border="1">
<tr>
|用户名:|<sf:input path="username"/><sf:errors path="username"/>
</tr>
<tr>
|用户密码:|<sf:password path="password"/><sf:errors path="password"/>
</tr>
<tr>
|用户昵称:|<sf:input path="nickname"/>
</tr>
<tr>
|用户邮箱:|<sf:input path="email"/><sf:errors path="email"/>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="用户添加"/>
</td>
</tr>
</table>
</sf:form>
</body>
</html>

 

  list.jsp 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!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>用户列表</title>
</head>
<body>
<table width="700" align="center" border="1">
<tr>
|用户标识:${pagers.total }|用户名|用户昵称|用户密码|用户邮箱
|操作
</tr>
<c:if test="${pagers.total le 0 }">
<tr>
<td colspan="6">目前还没有用户数据</td>
</tr>
</c:if>
<c:if test="${pagers.total gt 0}">
<c:forEach items="${pagers.datas }" var="u">
<tr>
|${u.id }|${u.username }
|[${u.nickname }](${u.id })
|${u.password }|${u.email }
|[更新](${u.id }/update)&nbsp;[删除](${u.id }/delete)
</tr>
</c:forEach>
<tr>
<td colspan="6">
<jsp:include page="/inc/pager.jsp">
<jsp:param value="users" name="url"/>
<jsp:param value="${pagers.total}" name="items"/>
</jsp:include>
</td>
</tr>
</c:if>
</table>
</body>
</html>

 

   show.jsp 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!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>用户[${user.nickname }]详细信息</title>
</head>

<body>
<table width="700" align="center" border="1">
<tr>
|用户标识:|${user.id }
</tr>
<tr>
|用户名:|${user.username }
</tr>
<tr>
|用户密码:|${user.password }
</tr>
<tr>
|用户昵称:|${user.nickname }
</tr>
<tr>
|用户邮箱:|${user.email }
</tr>
</table>
</body>
</html>

 

  update.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="sf" uri="http://www.springframework.org/tags/form" %>
<!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>用户更新</title>
</head>
<body>
<sf:form method="post" modelAttribute="user">
<table width="700" align="center" border="1">
<tr>
|用户名:|${user.username }<sf:hidden path="username"/>
</tr>
<tr>
|用户密码:|<sf:password path="password"/><sf:errors path="password"/>
</tr>
<tr>
|用户昵称:|<sf:input path="nickname"/>
</tr>
<tr>
|用户邮箱:|<sf:input path="email"/><sf:errors path="email"/>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="用户更新"/>
</td>
</tr>
</table>
</sf:form>
</body>
</html>

 

分页结构

 

5.在src/目录下建立包org.common.model

   *model包中一般放的是实体类,这些类定义了一些基本的属性以及简单的get/set方法,这些类和数据库中的表存在对应关系*

**  一般都是javabean对象,例如与数据库的某个表相关联。**

**  **

   先写User类,文件名字为User.java,其中就是简单的get方法和set方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package org.common.model;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity //如果我们当前这个bean要设置成实体对象,就需要加上Entity这个注解
@Table(name="t_user") //设置数据库的表名
public class User {
private int id;
private String username;
private String nickname;
private String password;
private String email;

//(建议不要在属性上引入注解,因为属性是private的,如果引入注解会破坏其封装特性,所以建议在getter方法上加入注解)
@Id //定义为数据库的主键ID  
@GeneratedValue //ID的生成策略为自动生成
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}

}

   接下来只需要在hibernate.cfg.xml文件里面将该实体类加进去即可:

1
2
3
4
5
<!-- 基于annotation的配置 -->
<mapping class="com.xiaoluo.bean.User"/>
<!-- 基于hbm.xml配置文件 -->
<mapping resource="com/xiaoluo/bean/User.hbm.xml"/>

  但是,我们采取的方法是使用Spring配置数据源,即在Spring容器中定义数据源,指定映射文件、设置hibernate控制属性等信息,完成集成组装的工作,完全抛开hibernate.cfg.xml配置文件,具体的方法就是在beans.xml文件中加入

 

其中的Spring注解hibernate实体方法

1
2
3
4
5
6
7
8
<property name="annotatedClasses">
<list>
<value>com.sise.domain.Admin</value>
<value>com.sise.domain.Remind</value>
<value>com.sise.domain.User</value>
</list>
</property>

 可以使用下面的来替代

1
2
3
4
5
<!-- 设置Spring取那个包中查找相应的实体类,指定hibernate实体类映射文件 -->
<property name="packagesToScan">
<value>org.common.model</value>
</property>

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<!-- 导入Src目录下的jdbc.properties文件 -->
<context:property-placeholder location="classpath:jdbc.properties" />
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<!-- 配置连接池的初始值 -->
<property name="initialSize" value="1" />
<!-- 连接池的最大值 -->
<!-- <property name="maxActive" value="500"/> -->
<!-- 最大空闲时,当经过一个高峰之后,连接池可以将一些用不到的连接释放,一直减少到maxIdle为止 -->
<!-- <property name="maxIdle" value="2"/> -->
<!-- 当最小空闲时,当连接少于minIdle时会自动去申请一些连接 -->
<property name="minIdle" value="1" />
<property name="maxActive" value="100" />
<property name="maxIdle" value="20" />
<property name="maxWait" value="1000" />
</bean>

<!--创建Spring的SessionFactory工厂 -->
<!-- 如果使用的是Annotation的方式,不能使用LocalSessionFactoryBean,而应该使用 org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">

<!-- 注入数据源 -->
<property name="dataSource" ref="dataSource" />

<!-- 设置Spring取那个包中查找相应的实体类,指定hibernate实体类映射文件 -->
<property name="packagesToScan">
<value>org.common.model</value>
</property>

<!-- 指定hibernate配置属性-->
<property name="hibernateProperties">
<!-- <value> hibernate.dialect=org.hibernate.dialect.HSQLDialect </value> -->
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.format_sql">false</prop>
</props>
</property>
</bean>

 

6.在src/目录下建立包org.common.dao

**  在dao中,写与数据库的操作,增删改查等方法
**

**  首先写IUserDao接口,文件名为IUserDao.java**

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package org.common.dao;

import java.util.List;

import org.common.model.Pager;
import org.common.model.User;

public interface IUserDao { //IUserDao接口
public void add(User user);
public void update(User user);
public void delete(int id);
public User load(int id);
public List<User> list();
public Pager<User> find();
public User loadByUsername(String username);
}

   同时,还要在包org.common.model下加上分页的类,文件名是Page.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package org.common.model;

import java.util.List;

public class Pager<T> { //分页
private List<T> datas;
private int offset;
private int size;
private long total;

public List<T> getDatas() {
return datas;
}
public void setDatas(List<T> datas) {
this.datas = datas;
}
public int getOffset() {
return offset;
}
public void setOffset(int offset) {
this.offset = offset;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public long getTotal() {
return total;
}
public void setTotal(long total) {
this.total = total;
}
}

   在写完分页的类之后,接下来写DAO返回给service的东西,文件名是SystemContext.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package org.common.model;

public class SystemContext { //传分页需要把当前页和每页显示多少条
private static ThreadLocal<Integer> offset = new ThreadLocal<Integer>();
private static ThreadLocal<Integer> size = new ThreadLocal<Integer>();

public static Integer getOffset() {
return offset.get();
}
public static void setOffset(Integer _offset) {
offset.set(_offset);
}
public static void removeOffset() {
offset.remove();
}

public static Integer getSize() {
return size.get();
}
public static void setSize(Integer _size) {
size.set(_size);
}
public static void removeSize() {
size.remove();
}

}

 

  接下来实现IUserDao接口写UserDao类,文件名是UserDao.java

  在实现的同时,还要继承HibernateDaoSupport,extends HibernateDaoSupport

  但是在spring 的HibernateDaoSupport中,setSessionFactory是使用final 修饰的,无法重写,沒有办法使用注解的方式注入sessionFactroy

  所以可以自己定义一个方法,这个方法去调用hibernateDaoSupport 中的setSessionFacotry方法,达到注入sessionFactory 的目的。

  因此我定义如下的类:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
package org.common.dao;

import java.util.List;

import javax.annotation.Resource;

import org.common.model.Pager;
import org.common.model.SystemContext;
import org.common.model.User;
import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.stereotype.Repository;

@Repository("userDao") //申明一个DAO
public class UserDao extends HibernateDaoSupport implements IUserDao {

//但是在spring 的HibernateDaoSupport中,setSessionFactory是使用final 修饰的,无法重写,沒有办法使用注解的方式注入sessionFactroy
//所以可以自己定义一个方法,这个方法去调用hibernateDaoSupport 中的setSessionFacotry方法,达到注入sessionFactory 的目的。
@Resource
public void setSuperSessionFactory(SessionFactory sessionFactory) {
this.setSessionFactory(sessionFactory);
}

@Override
public void add(User user) {
this.getHibernateTemplate().save(user);
}

@Override
public void update(User user) {
this.getHibernateTemplate().update(user);
}

@Override
public void delete(int id) {
User user = this.load(id);
this.getHibernateTemplate().delete(user);
}

@Override
public User load(int id) {
return this.getHibernateTemplate().load(User.class, id);
}

@SuppressWarnings("unchecked")
@Override
public List<User> list() {
return this.getSession().createQuery("from User").list();
}

@SuppressWarnings("unchecked")
@Override
public Pager<User> find() {
int size = SystemContext.getSize();
int offset = SystemContext.getOffset();
Query query = this.getSession().createQuery("from User");
query.setFirstResult(offset).setMaxResults(size);
List<User> datas = query.list();
Pager<User> us = new Pager<User>();
us.setDatas(datas);
us.setOffset(offset);
us.setSize(size);
long total = (Long)this.getSession()
.createQuery("select count(*) from User")
.uniqueResult();
us.setTotal(total);
return us;
}

@Override
public User loadByUsername(String username) {
return (User)this.getSession().createQuery("from User where username=?")
.setParameter(0, username).uniqueResult();
}

}