这个综合案例是Web应用种常见的业务:用户登录。
1.用户登录案例需求
- 1.编写login.html登录页面,username & password 两个输入框
- 2.使用Druid数据库连接池技术,操作mysql,查询dong数据库中user表
- 3.使用JdbcTemplate技术封装JDBC
- 4.登录成功跳转到SuccessServlet展示:登录成功!用户名,欢迎您
- 5.登录失败跳转到FailServlet展示:登录失败,用户名或密码错误
2.案例分析
案例结构图
3.开发步骤
3.1 创建数据库环境
根据需求,建立一个dong数据库,在数据下创建user表。
CREATE DATABASE dong;
USE dong;
CREATE TABLE USER(
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(32) UNIQUE NOT NULL,
PASSWORD VARCHAR(32) NOT NULL
);
INSERT INTO USER(username,PASSWORD) VALUES('zhangsan',123456);
user表;
3.2 创建项目,导入jar包
百度网盘:jar包资源,提取码:wdgi
3.3 编写html页面,配置文件
login.html页面
- login.html中form表单的action路径的写法:虚拟目录+Servlet的资源路径。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/LoginServlet" method="post">
用户账号:<input type="text" placeholder="请输入账号" name="username"><br>
用户密码:<input type="text" placeholder="请输入密码" name="password"><br>
<input type="submit" value="登录">
</form>
</body>
</html>
druid.properties配置文件
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/dong?useSSL=false
username=root
password=201703457
initialSize=5
maxActive=10
maxWait=3000
3.4 结构目录
3.5 创建包com.dong.domain,创建类User
/**
* 用户实体类
*/
public class User implements java.io.Serializable {
private int id;
private String username;
private String password;
public User() {
}
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;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
3.6 创建包com.dong.util,编写工具类JDBCUtils
/**
* JDBC工具类,使用Druid连接池
*/
public class JDBCUtils {
private static javax.sql.DataSource ds;
static {
try {
//1.加载配置文件
java.util.Properties prop = new java.util.Properties();
//使用ClassLoader加载配置文件,获取字节输入流
java.io.InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties");
prop.load(is);
//2.初始化数据库连接池对象
ds = DruidDataSourceFactory.createDataSource(prop);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取连接池对象
*
* @return
*/
public static javax.sql.DataSource getDataSource() {
return ds;
}
/**
* 获取数据库连接对象
*
* @return
*/
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
}
3.7 创建包com.dong.dao,创建类UserDao,提供login方法
/**
* 操作数据库的类
*/
public class UserDao {
//声明JDBCTemplate对象共用
private JdbcTemplate jdbcTemplate = new JdbcTemplate(JDBCUtils.getDataSource());
/**
* 登录方法
*
* @param loginUser
* @return user包含用户全部数据,没有查询到,放回null
*/
public User login(User loginUser) {
try {
//1.编写sql语句
String sql = "select * from user where username=? and password=?";
//2.调用JDBCTemplate对象的查询方法
User user = jdbcTemplate.queryForObject(sql //sql语句
, new BeanPropertyRowMapper<User>(User.class) //RowMapper接口实现类,将数据自动封装成指定对象
, loginUser.getUsername() //sql参数
, loginUser.getPassword()); // sql参数
return user;
} catch (Exception e) {
e.printStackTrace();//以后会将异常记录到日志文件中
return null;
}
}
}
3.8 创建包com.dong.test,创建类UserDaoTest,测试login方法
public class UserDaoTest {
/**
* 测试login方法能否查询成功
*/
@Test
public void loginTest(){
User loginuser = new User();
loginuser.setUsername("zhangsan");
loginuser.setPassword("123456");
UserDao dao = new UserDao();
User user = dao.login(loginuser);
System.out.println(user);
}
}
3.9 编写com.dong.web.servlet.LoginServlet类
@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.设置解码格式
req.setCharacterEncoding("utf-8");
//2.获取请求体参数username和password
String username = req.getParameter("username");
String password = req.getParameter("password");
//3.将username和password封装成User对象
User loginuser = new User();
loginuser.setUsername(username);
loginuser.setPassword(password);
//4.调用UserDao的login方法
UserDao dao = new UserDao();
User user = dao.login(loginuser);
//5.判断user是否为null
if (user==null){
//登录失败跳转到FailServlet
req.getRequestDispatcher("/FailServlet").forward(req,resp);
}else {
//登录成功,将用户信息存在request域,跳转SuccessServlet
req.setAttribute("user",user);
req.getRequestDispatcher("/SuccessServlet").forward(req,resp);
}
}
}
3.10 编写FailServlet和SuccessServlet类
@WebServlet(name = "FailServlet", urlPatterns = "/FailServlet")
public class FailServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//在页面输出:登录失败,用户名或密码错误!
//设置编码格式
response.setContentType("text/html;charset=utf-8");
//输出
response.getWriter().write("登录失败,用户名或密码错误!");
}
}
@WebServlet(name = "SuccessServlet", urlPatterns = "/SuccessServlet")
public class SuccessServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//在页面输出:登录成功,用户名xxx欢迎您!
//设置编码格式
response.setContentType("text/html;charset=utf-8");
//获取请求域中存储的数据
User user = (User) request.getAttribute("user");
//输出
response.getWriter().write("登录成功,用户名"+user.getUsername()+"欢迎您!");
}
}
启动服务器
1.访问login.html
2.点击登录,提交表单数据
登录成功:
登录失败:
4.程序优化
当请求参数非常多的时候,比如用户的注册页面发向服务器的请求,包含很多用户的信息数据。
像这种情况下,会需要大量而枯燥的获取getParameter获取参数的代码,每次获取一个参数值,效率低,而且还需要将数据都封装到JavaBean(User)对象中,重复操作太多。
现在对LoginServlet类做如下优化,简化上述操作:
1.使用方法Map<String,String[]> getParameterMap()
: (重点)获取所有请求参数的map集合。
2.使用BeanUtils工具类,简化数据封装。
简单了解一下这个工具类,BeanUtils
位于org.apache.commons.beanutils.BeanUtils
下面,是专门提供给我们用于封装JavaBean的。
需要了解它里面的三个方法:都是静态方法
setProperty(Object bean, String name, Object value)
:设置bean对象中name属性的值getProperty(Object bean, String name)
:获取bean对象中name属性的值populate(Object bean, Map map)
:(重点)将map集合的键值对信息,封装到对应的JavaBean对象中。
这个方法会遍历map<key, value>中的key,如果bean中有这个属性,就把这个key对应的value值赋给bean的属性。
优化后的LoginServlet类:
@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.设置解码格式
req.setCharacterEncoding("utf-8");
/*//2.获取请求体参数username和password
String username = req.getParameter("username");
String password = req.getParameter("password");
//3.将username和password封装成User对象
User loginuser = new User();
loginuser.setUsername(username);
loginuser.setPassword(password);*/
//2.获取所有的请求体参数,当请求参数非常多的时候,非常方便
Map<String, String[]> map = req.getParameterMap();
//3.创建User对象
User loginuser = new User();
//3.1使用BeanUtils封装,提供的bean工具类自动封装map集合中数据为JavaBean对象
try {
BeanUtils.populate(loginuser,map);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
//4.调用UserDao的login方法
UserDao dao = new UserDao();
User user = dao.login(loginuser);
//5.判断user是否为null
if (user==null){
//登录失败跳转到FailServlet
req.getRequestDispatcher("/FailServlet").forward(req,resp);
}else {
//登录成功,将用户信息存在request域,跳转SuccessServlet
req.setAttribute("user",user);
req.getRequestDispatcher("/SuccessServlet").forward(req,resp);
}
}
}
5.JavaBean
如果对JavaBean不熟悉,这里简单回顾一下
5.1 JavaBean:标准的Java类,这样的类一般会有以下几个要求:
- 1.类必须被public修饰
- 2.必须提供空参和全参的构造器
- 3.成员变量必须使用private修饰
- 4.提供公共setter和getter方法
5.2 JavaBean的功能,就是封装数据。
5.3 了解JavaBean中属性和成员变量的概念
成员变量:就是我们声明在类中的变量,像private String name;等
属性:setter和getter方法截取后的产物,截取后的产物(属性)大多数情况下与成员变量在名称上一致。
截取过程,例如getHehe() --> Hehe–> hehe,setHehe() --> Hehe–> hehe;
在User实体类添加以下代码,并修改toString()方法,加上输出gender的值:
private String gender;
public void setHehe(String gender){
this.gender = gender;
}
public String getHehe(){
return gender;
}
编写一个测试方法,验证属性和成员方法的区别:
5.3.1 设置bean的成员变量
@Test
public void test(){
User user = new User();
try {
BeanUtils.setProperty(user,"gender","male");
System.out.println(user);
String gender = BeanUtils.getProperty(user, "gender");
System.out.println(gender);
} catch (Exception e) {
e.printStackTrace();
}
}
运行结果:
原因是没有属性gender,没有setGender()和getGender()方法,也就是没有setter和getter方法截取后的产物为gender的属性。
需要加上setGender()和getGender()方法后,才能设置bean的成员变量gender。
private String gender;
public void setGender(String gender){
this.gender = gender;
}
public String getGender(){
return gender;
}
public void setHehe(String gender){
this.gender = gender;
}
public String getHehe(){
return gender;
}
再次运行测试方法,结果:
5.3.2 设置bean的属性
在User实体类添加以下代码,并修改toString()方法,加上输出gender的值:
private String gender;
public void setHehe(String gender){
this.gender = gender;
}
public String getHehe(){
return gender;
}
测试方法
@Test
public void test1(){
User user = new User();
try {
BeanUtils.setProperty(user,"hehe","male");
System.out.println(user);
String gender = BeanUtils.getProperty(user, "hehe");
System.out.println(gender);
} catch (Exception e) {
e.printStackTrace();
}
}
再次运行测试方法,结果:
可以看到bean中没有hehe成员变量,但是有hehe属性,属性值为male,并且成员变量gender的值也被设置为male了。
因为有setHehe()和getHehe()方法,setHehe()和getHehe()方法截取后的产物为hehe的属性。setProperty()、getProperty()方法底部会调用hehe对应的setter和getter方法,所有可以设置和获取属性值hehe。
可以证明JavaBean中属性和成员方法的区别,不清楚也没有关系,大多数情况下属性与成员变量是一致的。
介绍完毕,非常简单的一个案例,但知识点却不少,可以很好的融会贯通一些点。学无止境,每天都要全力以赴!
推荐阅读:
【JavaWeb】HTTP协议详细
【JavaWeb】Request对象详解
欢迎点赞评论,指出不足,笔者由衷感谢哦!~