今日内容
1. Servlet
2. HTTP协议
3. Request
一.Servlet:
1. 概念
2. 步骤
3. 执行原理
4. 生命周期
5. Servlet3.0 注解配置
6. Servlet的体系结构
Servlet -- 接口的两个实现类:
1. GenericServlet -- 是一个抽象类实现了Servlet接口
public abstract class GenericServlet extends Object implements Servlet,
2. HttpServlet -- 是一个抽象类继承了GenericServlet
public abstract class HttpServlet extends GenericServlet
1. GenericServlet:将Servlet接口中的其他方法做了默认空实现,只将service()方法做了
抽象。将来定义Servlet类时,可以继承GenericServlet,实现service()方法即可。
2. HttpServlet:对http协议的一种封装,简化操作。
* 定义类继承HttpServlet
* 复写doGet()/doPost()方法
因为要根据具体的请求方式作出相应的操作,这样就不用在自己判断是哪种请求方式了。
7. Servlet的相关配置
1. urlpartten:Servlet的访问路径
* 一个Servlet可以定义多个访问路劲:@WebServlet({"/d4", "/dd4", "/77demo4"})
* 路径的定义规则:
1. /xxx
2. /xxx/xxx:多层路径,目录结构
3. *.do
二.HTTP:
* 概念:Hyper Text Transfer Protocol 超文本传输协议
* 传输协议:定义了客户端和服务器端通信时,发送数据的格式。
发送的数据指的是:请求消息和响应消息的格式。
* http协议特点:
1. 基于TCP/IP的高级协议
2. 默认端口号是:80
如果我们设置服务器软件(tomcat)的端口号是80那么该端口号就可以省略不写。
http://www.itcast.cn:80 === http://www.itcast.cn
3. 基于请求/响应模型的:一次请求对应一次响应
4. 无状态的:每次请求之间相互独立,不能交互数据。
* 历史版本
1.0:每一次请求/响应都会建立新的连接
1.1:复用连接
* 请求消息数据格式
1. 请求行
请求方式 请求URL 请求的协议/版本
GET /login.html HTTP/1.1
* 请求方式:
* HTTP有7种请求方式,常用的有两种
* GET:
1. 请求参数在请求行中,在URL后,所以请求不太安全
Request URL: http://localhost/day0428_Servlet_http_Request/demo3?username=awdq
2. 请求的URL是有限制的
* POST
1. 请求参数在请求体中,相对安全
2. 请求的UR没有限制的
2. 请求头:客户端浏览器告诉服务器一些信息。
请求头名称 : 请求头值
* 常见的请求头:
Host: localhost
我请求的主机是本地主机
User-Agent: 浏览器告诉服务器,我访问你使用的浏览器版本信息。
可以在服务器端获取该头的信息,解决浏览器的兼容性问题。
Accept : 告诉服务器,浏览器可以接收哪些类型的信息。
Referer: http://localhost/day0428_Servlet_http_Request/login.html
告诉服务器,我(当前请求)从哪里来?
* 作用:
1. 防止被盗链。
if(Referer.equals("优酷首页"){
我就让你看电影
}else {
是盗链来的请求。
}
2. 统计工作。
Connection: keep-alive
该连接是活着的,所以可以被复用。(HTTP 1.1版本特点)
3. 请求空行
空行,起分隔作用请求头和请求体的。
4. 请求体(正文)
* 封装POST请求消息的请求参数的
所以GET请求没有请求体,只有上面2部分。
* 响应消息数据格式
Request:
* request和response对象的原理:
1.tomcat服务器会根据请求URL中的资源路劲,创建对应的ServletDemo1对象。
2.tomcat服务器会创建request对象和response对象。request队形中封装请求消息数据。
3.tomcat将request和response两个对象传递给service方法作为参数,并且调用service方法。
4.程序员(我们),可以通过request对象获取请求消息数据。通过response对象设置响应消息数据。
5.服务器在给浏览器做出响应之前,会从response对象中拿程序员设置的响应消息数据,传给浏览器。
* request和response对象是由服务器创建的。我们来操作它们。
* request和response对象十来获取请求消息,response对象是来设置响应消息。
* request对象的继承体系结构。
public interface HttpServletRequest extends ServletRequest
public class RequestFacade implements HttpServletRequest(在tomcat的源码里)
ServletRequest: -- 接口
|继承
HTTPServletRequest -- 接口
|实现
org.apache.catalina.connector.RequestFacade -- 类(tomcat编写的)
tomcat通过这个类来创建HTTPServletRequest对象传递给service方法。
* request功能:
1.获取请求消息数据。
1. 获取请求行数据
* GET http://localhost/day0428_Servlet_http_Request/demo?name=zhangsan HTTP/1.1
* 方法:
1. 获取请求方式:GET
* String getMethod()
2. 获取虚拟目录:/day0428_Servlet_http_Request
* String getContextPath()
3. 获取Servlet路径(资源路径):/demo
* String getServletPath()
4. 获取get方式的请求参数:name=zhang
* String getQueryString()
5. 获取请求的URI/URL
* URI:统一资源标识符
* URL:统一资源定位符
* String getRequestURI():/day0428_Servlet_http_Request/demo
* StringBuffer getRequestURL():
http://localhost/day0428_Servlet_http_Request/demo
6. 获取协议及版本号
* String getProtocol()
7. 获取客户机的ip地址
* String getRemoteAddr()
2. 获取请求头数据
* 方法:
* String getHeader(String name):通过请求头的名称获取请求头的值
* Enumeration<String> getHeaderNames():获取所有请求头名称。
Interface Enumeration<E> 是一个泛型接口,类似于迭代器。也有俩个方法:
boolean hasMoreElements()
E nextElement()
3. 获取请求体数据::是HttpServletRequest父接口ServletRequest中的方法
* 请求体只有POST请求方式才有请求体,在请求体中封装了POST请求的参数
* 步骤
1. 获取流对象::是HttpServletRequest父接口ServletRequest中的方法
* BufferedReader getReader():获取字符输入流,只能操作字符数据
* ServletInputStream getInputStream() :获取字节输入流,可以操作
所有类型数据
在文件上传知识点再讲解
2. 再从流对象中拿数据
2.其他功能:
1.获取请求参数的通用方式:是HttpServletRequest父接口ServletRequest中的方法。
这里不是获取请求体的内容了,而是无论你是GET还是POST都是直接获取请求参数。
1. String getParameter(String name) : 根据参数名称获取参数值
2. String[] getParameterValues(String name):根据参数名称获取参数值的数组
hobby=xx&hobby=game&hobby=music
3. Enumeration<String> getParameterNames():获取所有的参数名称
4. Map<String, String[]> getParameterMap():获取所有参数的map集合(键值对)
* 中文乱码问题
* get方式:tomcat8已经将get方式乱码问题解决了。即GET方式不会出现中文乱码
* post方式:内部通过流获取参数值。
* 解决:在获取参数前,设置request的编码
req.setCharacterEncoding("utf-8");
2.请求转发:一种在服务器内部的资源跳转的方式
如果实现一个需求需要多个Servlet,比如day0428项目下有AServlet和BServlet。
AServlet实现一部分后,BServlet实现后面的一部分。那么浏览器访问AServlet后要
跳转到BServlet。这就是跳转的一种方式。
1. 步骤:
1. 通过request对象获取请求转发器对象:
RequestDispatcher getRequestDispatcher(String path)
2. 使用RequestDispatcher对象进行转发:
forward(ServletRequest request, ServletResponse response)
2. 特点:
1. 资源虽然跳转了,但是浏览器地址栏路径没有发生变化
2. 转发只能跳转到当前服务器内部的资源
3. 转发只发送了一次请求(虽然访问了两个资源)。即多个资源使用了一个请求。
3.共享数据
* 域对象:一个有作用范围的对象,可以在范围内共享数据。
* request域:代表了一次请求的范围。一般用于请求转发的多个资源中共享数据。
* 方法:
1. serAttribute(String name, Object obj):存储数据(键值对形式)
2. getAttribute(String name): 通过键获取值
3. removeAttribute(String name) : 通过建来移除键值对。
4.获取ServletContext:
ServletContext getServletContext()
案例:用户登录
* 用户登录案例需求:
1.编写login.html登录页面
username & password 两个输入框
2.使用Druid数据库连接池技术,操作mysql,day14数据库中user表
3.使用JdbcTemplate技术封装JDBC
4.登录成功跳转到SuccessServlet展示:登录成功!用户名,欢迎您
5.登录失败跳转到FailServlet展示:登录失败,用户名或密码错误
* 分析
* 开发步骤
1. 创建项目,导入html页面,配置文件,jar包
2. 创建数据库环境
CREATE DATABASE day0428;
USE day0428;
CREATE TABLE USER(
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(32) UNIQUE NOT NULL,
PASSWORD VARCHAR(32) NOT NULL
);
3. 创建包:cn.itcast.domain,创建一个类user对应user表
```
package cn.itcast.domain;
/*
用户的JavaBean(实体类)
*/
public class User {
private int id;
private String username;
private String password;
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;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
```
4.创建包:cn.itcast.util; JDBC的工具类:使用的是Durid连接池
```
public class JDBCUtils {
//定义一个静态的数据库连接池对象
private static DataSource ds;
static {
try {
//1.加载配置文件:pro就有了配置文件druid.properties的数据了。封装成了键值对的集合
Properties pro = new Properties();
//使用ClassLoader加载配置文件,获取字节输入流
InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties");
pro.load(is);
//2.初始化连接池对象
ds = DruidDataSourceFactory.createDataSource(pro);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 1、获取连接池对象
*/
public static DataSource getDataSource(){
return ds;
}
/**
* 2、获取连接Connection对象
*/
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
}
```
5.创建包:cn.itcast.dao,创建一个类UserDao,提供login的方法(操作数据库的方法)。
```
public class UserDao {
//声明JDBCTemplate对象共用
private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
/**
* 登录方法
* @param loginUser:User对象:只有用户名和密码
* @return user:包含用户的全部数据。没有查询到,返回null
*/
public User login(User loginUser){
try {
//1.编写sql
String sql = "select * from user where username = ? and password = ?";
//2.调用query方法:
User user = template.queryForObject(sql,
new BeanPropertyRowMapper<User>(User.class),
loginUser.getUsername(), loginUser.getPassword());
return user;
} catch (DataAccessException e) {
e.printStackTrace();
//查询没有该数据:不让它报异常,让他返回null
return null;
}
}
}
```
6.编写cn.itcast.web.servlet.LoginServlet类。
```
@WebServlet("/loginSerlvet")
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.设置编码
req.setCharacterEncoding("utf-8");
//2.获取请求参数
String username = req.getParameter("username");
String password = req.getParameter("password");
//3.封装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
if(user == null){
//登录失败
req.getRequestDispatcher("/failServlet").forward(req,resp);
}else {
//登陆成功
//存储数据
req.setAttribute("user", user);
//转发
req.getRequestDispatcher("/successServlet").forward(req,resp);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}
```
7.注意:login.html中form表单的action路径的写法:
* 虚拟目录+Servlet的资源路径。
8.BeanUtils工具类,完成(有多个请求参数)数据封装,简化操作。
* 用于封装JavaBean的
```
/*
//2.获取请求参数
String username = req.getParameter("username");
String password = req.getParameter("password");
//3.封装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.2.使用BeanUtils封装:将map里面的数据封装到成一个User对象。
try {
BeanUtils.populate(loginUser, map);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
```
1. JavaBean:标准的Java类
1.类必须被public修饰
2.必须提供空参的构造器
3.提供公共setter和getter方法
4.一般放在domain/entity包下
5.成员变量必须private修饰
2.功能:封装数据
3.概念:
成员变量:
private int id;
private String username;
private String password;
属性:在大多数情况下就是成员变量
setter和getter方法截取后的产物
例如:
getUsername()--->Username--->username
//成员变量:gender
private String gender;
//属性;Hehe
public String getHehe() {
return gender;
}
public void setHehe(String gender) {
this.gender = gender;
}
4.方法
1.setProperty():是给属性二不是成员变量
//相当于给user的username属性赋值:zhangsan
BeanUtils.setProperty(user, "username", "zhangsan");
//gender之不会变:因为操作的是gender成员变量
BeanUtils.setProperty(user, "gender", "male");
//gender值会变,因为操作的是属性setHehe()/getHehe()
BeanUtils.setProperty(user, "hehe", "male");
2.getProperty()
String gender = BeanUtils.getProperty(user, "hehe");
3.populate(Object obj, Map map):
将map集合的键值对信息,封装到对应的JavaBean对象中。
//使用BeanUtils封装:将map里面的数据封装到成一个User对象。
BeanUtils.populate(loginUser, map);