1.需求及技术分析

登录页面需要完成如下需求:

在页面上输入用户名和密码,提交到服务器上,服务器取用用户名和密码去数据库中查找是否存在该用户。若用户存在,提示登录成功并转接到首页;若不存在,提示用户名或者密码错误。

技术分析:

实现该需求,需要如下技术:表单,servlet,请求(request)和响应(response)。

其中,表单的作用是:

1)收集用户数据;

2)所有的字段要想提交到服务器端必须有Name属性;

3)提交的地址为action

4)请求方式为post

2.servlet

servlet是动态的web开发技术,本质上是运行在服务器端的一个java小程序(类),主要用于处理业务逻辑,生成共台的web内容。

2.1编写一个servlet步骤

1)编写一个类; a)继承HttpServlet; b)重写doGet或者doPost方法;

2)编写配置文件;

a)注册servlet;

b)绑定路径

3)访问

http://主机:端口/项目名/绑定的路径

2.2 接受参数

格式为key=value

String value=request.getParameter("key")

例如:

http://localhost:8080/loginout/hello?username=tom

request.getParameter("username")就可以获取tom的值

2.3 回写内容

response
response.getWriter().print("success";)

如:

resp.getWriter().print("data:"+value);

如果回写的内容中存在中文字符,需要在语句前增加以下内容:

resp.setContentType("text/html;charset=utf-8");
resp.getWriter().print("data:"+value);

全部代码如下:

public class RequestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//接受参数
String value = req.getParameter("username");
//回写数据
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().print("data:"+value);
System.out.println(value);
}
}

2.4 servlet生命周期

servlet常用方法有三种:分别为初始化、服务以及销毁三个,如下所示。生命周期详见程序中注释

public class LifeServlet implements Servlet {
/**
* 销毁方法
* 执行者:服务器
* 执行次数:只执行一次
* 执行时机:当servlet被移除或者服务器正常关闭的时候
*/
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public ServletConfig getServletConfig() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getServletInfo() {
// TODO Auto-generated method stub
return null;
}
/**
* 初始化方法
* 执行者:服务器
* 执行次数:一次
* 执行时机 :默认第一次访问的时候
*/
@Override
public void init(ServletConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
/**
* 服务方法
* 执行者:服务器
* 执行次数:请求一次执行一次
* 执行时机:请求来的时候
*/
@Override
public void service(ServletRequest arg0, ServletResponse arg1) throws ServletException, IOException {
// TODO Auto-generated method stub
}

servlet是单实例多线程的,默认第一次访问的时候,服务器创建servlet,并调用Init实现初始化操作,并调用一次service方法。每当请求来的时候,服务器就会创建一个线程,调用service方法执行自己的业务逻辑。当servlet被移除的时候服务器正常关闭的时候,服务器就会调用servlet的destroy方法实现销毁操作。

2.5 url-pattern配置

配置共有三种方式:

1)完全匹配,必须以"/"开始,如/hello,/a/b/c

2)目录匹配,必须以"/"开始,以'*'结束,例如/a/*,/*;

3)后缀名匹配,以"*"开始,以字符结尾,例如*.jsp,*.do,*.action

优先级:

完全匹配>目录匹配>后缀名匹配

练习:

1.当请求URL为"/abc/a.html","/abc/*"和"/*"都匹配,此时Servlet引擎可以调用/abc/*;

2.当请求URL为"/abc"时,"/abc"和"/*"都匹配,此时Servlet引擎可以调用/abc;

3.当请求URL为"/abc/a.do"时,"/abc/*"和"/*.do"都匹配,此时Servlet引擎可以调用/abc/*;

4.当请求URL为"/a.do"时,"/*"和"/*.do"都匹配,此时Servlet引擎可以调用/*;

5.当请求URL为"/xxx/yyy/a.do"时,"/*"和"/*.do"都匹配,此时Servlet引擎可以调用/*;

2.6 初始化时机

servlet标签有一个子标签load-on-startup,用于修改servlet的初始化时机,取值为正整数,值越大优先级就会越低。

当我们配置文件里面没有指定配置的话,会查找tomcat的web.xml文件,若请求我们自己的项目处理不了,tomcat的默认的servlet就会帮我们处理信息。

3.设计步骤分析

1)现有数据库和表

package com.itcast.domain;
import java.util.Date;
public class User {
private int id;
private String username;
private String password;
private String email;
private String name;
private String sex;
private Date birthday;
private String hobby;
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 getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getHobby() {
return hobby;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
}

2)创建工程

3)复制页面,修改对应的html文件

(1)给用户名和密码添加name属性;

(2)修改表单的action属性

action="http://localhost/loginout/login"

注意:action值末尾的login与创建的servlet的路径必须一致;

添加method属性为

method="post"

本文案例如下:



请输入合法的邮箱地址



邮箱或密码不正确



登 录



立即注册

忘记密码



4)导入jar包:驱动 dbutils c3p0

调用的包有:

mchange-commons-java-0.2.3.4.jar;该jar包主要是为c3p0服务
mysql-connector-java-5.1.46-bin.jar;
c3p0-0.9.2.1.jar;
commons-dbutils-1.7.jar;

5)导入工具类和配置文件:dataSourceUtils和c3p0-config.xml

创建package:com.itcast.utils,放入程序DataSourceUtils.java,并在src文件夹下引入c3p0-config.xml。

注意:

需要对文件c3p0-config.xml中的数据库内容进行一定的修改。

6)创建servlet(LoginServlet:路径为"/login",需要完成如下功能:

(1)接受用户名和密码;

(2)调用service层(UserService)完成登录操作;

(3)提示信息

在src下创建com.itcast.web.servlet包,创建LoginServlet.java文件,内容为:

ublic class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1.设置编码格式
response.setContentType("text/html;charset=utf-8");
// 2.接受用户名和密码
String username = request.getParameter("username");
String password = request.getParameter("password");
// 3.调用userService里的login(username,password),返回值为User user
User user = null;
try {
user = new UserService().login(username, password);
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("网络异常,请稍后重试");
}
// 4.判断user是否为空
if (user == null) {
response.getWriter().print("用户名和密码不匹配");
} else {
response.getWriter().print(user.getUsername() + ":欢迎回来");
}
}
}
7)UserService完成功能:login(userName,password)并调用dao
package com.itcast.service;
import java.sql.SQLException;
import com.itcast.dao.UserDao;
import com.itcast.domain.User;
public class UserService {
public User login(String username, String password) throws SQLException {
// 调用dao
UserDao dao = new UserDao();
return dao.getUserByUsernameAndPwd(username, password);
}
}

9)dao层通过用户名和密码查询数据库

package com.itcast.dao;
import java.sql.SQLException;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import com.itcast.domain.User;
import com.itcast.utils.DataSourceUtils;
public class UserDao {
/**
*
* @param username
* @param password
* @return
* @throws SQLException
*/
public User getUserByUsernameAndPwd(String username, String password) throws SQLException {
// 创建queryrunner
QueryRunner qr = new QueryRunner(DataSourceUtils.getDataSource());
// 编写sql
String sql = "select * from user where username=? and password=?";
// 执行sql
User user = qr.query(sql, new BeanHandler<>(User.class), username, password);
return user;
}
}

4.定时更新功能实现

定时更新功能介绍如下:当我们登陆失败后,依旧提示“用户名与密码不匹配”,3秒后挑战至新的登录界面。

技术方面需要增加响应头设置,常见的响应头为refresh命令。 refresh格式为

refresh:秒数;url=跳转的路径

设置响应头

response.setHeader(String key, String value);设置字符串形式的响应头;

response.addHeader(String key, String value);追加响应头,若之前设置过,那么就进行追加,否则就进行设置;

实例

response.setHeader("refresh","3;url=/firstproject/index.html");

因此,实现更新操作步骤为:登陆失败后,修改业务逻辑,打印之后增加一个响应头信息。对LoginServlet.java更改如下:

package com.itcast.web.servlet;
import java.io.IOException;
import java.sql.SQLException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.itcast.domain.User;
import com.itcast.service.UserService;
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1.设置编码格式
response.setContentType("text/html;charset=utf-8");
// 2.接受用户名和密码
String username = request.getParameter("username");
String password = request.getParameter("password");
// 3.调用userService里的login(username,password),返回值为User user
User user = null;
try {
user = new UserService().login(username, password);
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("网络异常,请稍后重试");
}
// 4.判断user是否为空
if (user == null) {
response.getWriter().print("用户名和密码不匹配");
//增加自动跳转功能
response.setHeader("refresh", "3;url=/firstproject/index.html");
} else {
response.getWriter().print(user.getUsername() + ":欢迎回来");
}
}
}

5.统计登录次数

5.1 需求技术分析

统计登录次数就是在一个用户登陆成功时,获取之前登陆成功的总人数,将次数+1,在访问另一个servlet的时候,显示登陆成功的总人数。

在技术方面采用ServletContext命令,该命令作用为JVM为每一个“java项目”提供的上下文操作,或者说是全部管理者作用。

常用方法有:

设置值
setAttribute(String key, Object value);
获取值
Object getAttribute(String key);
//删除值
removeAttribute(String key);

5.2 步骤分析

1)在项目启动的时候,初始化登录次数,即,在LoginServlet的init()方法中获取全局管理者,将值初始化为0,放入servletContext中;

public void init() throws ServletException {
//获取全局管理者
ServletContext context = this.getServletContext();
//初始化次数
context.setAttribute("count", 0);
System.out.println("完成初始化");
}
2)登录成功后,在LoginServlet中获取全局管理者,并获取登录成功的总次数;
//获取全局管理者
ServletContext context = this.getServletContext();
//获取总此时
Integer newCount = (Integer) context.getAttribute("count");
3)将次数+1,然后将值设置回去
//获取全局管理者
ServletContext context = this.getServletContext();
//获取总此时
Integer newCount = (Integer) context.getAttribute("count");
//将次数+1
newCount++;
//将此书再次传入域对象中
context.setAttribute("count", newCount);

因此,增加统计登录人数之后的LoginServlet.java程序为:

package com.itcast.web.servlet;
import java.io.IOException;
import java.sql.SQLException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.itcast.domain.User;
import com.itcast.service.UserService;
public class LoginServlet extends HttpServlet {
@Override
/**
* 初始化登录次数
*/
public void init() throws ServletException {
//获取全局管理者
ServletContext context = this.getServletContext();
//初始化次数
context.setAttribute("count", 0);
System.out.println("完成初始化");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1.设置编码格式
response.setContentType("text/html;charset=utf-8");
// 2.接受用户名和密码
String username = request.getParameter("username");
String password = request.getParameter("password");
// 3.调用userService里的login(username,password),返回值为User user
User user = null;
try {
user = new UserService().login(username, password);
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("网络异常,请稍后重试");
}
// 4.判断user是否为空
if (user == null) {
response.getWriter().print("用户名和密码不匹配");
//增加自动跳转功能
response.setHeader("refresh", "3;url=/firstproject2/index.html");
} else {
response.getWriter().print(user.getUsername() + ":欢迎回来");
//获取全局管理者
ServletContext context = this.getServletContext();
//获取总此时
Integer newCount = (Integer) context.getAttribute("count");
//将次数+1
newCount++;
//将此书再次传入域对象中
context.setAttribute("count", newCount);
}
}
}

4)当访问showServlet的时候,获取全局管理者,获取登陆成功的总次数,然后在网页上打印出来。

package com.itcast.web.servlet;
import java.io.IOException;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 展示登录次数
*/
public class ShowServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置编码
response.setContentType("text/html;charset=utf-8");
//获取全部管理者
ServletContext context = this.getServletContext();
//获取登录的次数
Integer newCount = (Integer) context.getAttribute("count");
//在页面上进行打印
response.getWriter().print("登陆成功的总人数为:"+newCount);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}

6.servletconfig

servletcofig方法中,getServletContext()方法用于获取全局管理者。

servletconfig是由服务器创建的,在创建servlet的同时也创建了它,通过servlet的init(ServletConfig config)将config对象传递给servelt,由servlet的getServletConfig方法获取。

7.servletContext

ServeletContext为全局管理者,在一个项目的引用过程中,代表了当前的项目。当项目启动时,服务器为每一个web项目创建一个servletcontext对象,当项目被移除的时候或者服务器关闭的时候servletcontext对象被销毁。

7.1 作用

该方法的作用为

1.获取全局的初始化参数;

2.共享资源(xxxAttribute)

3.获取文件资源;

4.其他操作

7.2获取方式

获取servletcontext的方法共有两种

1.getServletConfig().getServletContext();

2.this.getServletContext();

其中第二种方法直接调用了方法一的接口,且是最为常用的方法。

7.3常用的方法

获取参数

1.String getInitParameter(String key):通过名称获取指定参数值;

2.Enumration getInitParameterNames():获取所有参数的名称

在跟标签下有一个context-param子标签,用来存放初始化参数

encoding

utf-8

返回文件

1.String getRealPath(String path):获取文件部署在tomcat上的真实路径(带tomcat路径);

2.getResourceAsStream(String path):以流的形式返回一个文件

获取文件的Mime类型,大型类/小类型

String getMimeType(String 文件类型)

8.通过类加载器获取文件

package com.itcast.path;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class PathServlet
*/
public class PathServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String pt = PathServlet.class.getClassLoader().getResource("1.txt").getPath();
System.out.println(pt);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
public static void main(String[] args) {
String pt = PathServlet.class.getClassLoader().getResource("1.txt").getPath();
System.out.println(pt );
}
}