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)访问
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 );
}
}