1.ServletAPI核心类和接口
步骤:
- 客户端发送ServletRequset请求由自定义的Servklet类接受
- 自定义类Servlet类需要继承HttpServlet去将ServletRequest请求转化为HtttpServletRequest请求
- 重写的void service()类需要传入转换的HttpServletRequest参数去实现doGet/doPost/doDelete…方法
2.Servlet处理用户流程
准备工作:
创建Servlet类的步骤
1.创建名为...Servlet的类名
2.继承 javax.servlet.http.HttpServlet类
3.重写doGet,daPost方法
4.配置当前Servlet的路径
public class TestServlet extends HttpServlet {
@Override
public void init(ServletConfig config) throws ServletException {
System.out.println("---------init");
super.init(config);
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("HttpService类定义的----------service");
super.service(req, resp);
}
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
System.out.println("Service接口定义的-----------Service");
super.service(req, res);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("HttpServletRequest---------dePost");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("ServletRequest---------dePost");
}
@Override
public void destroy() {
System.out.println("----------destroy");
super.destroy();
}
@Override
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPut(req, resp);
}
}
3.Servlet实例的生命周期
当客户端的请求到达Tomcat的时候,Tomcat会创建一个线程来接受,处理和响应用户的请求,当客户端在请求某个Servlet类的时候,线程需要通过这个类的实例去调用Service()方法,调用doGet/doPost方法来请求,那么Servlet实例是如何什么时候创建和销毁的呢?
Servlet实例的生命周期指的是一个Servlet类的实例从开始到销毁的过程
- Servlet类是单实例多线程的,Servlet只会实例化一个对象
- 如果Servlet类没有配置<load-on-startup>1</load-on-startup>
当客户端第一次请求对象的时候,创建Servlet类的实例化,调用service(ServiceRequest,ServiceResponse)方法--service(HttpServiceRequest,HttpServiceResponse)方法--doGet/doPost方法来处理客户端请求,当用户再一次访问的时候,不需要实例化,直接调用其中的方法
- 如果Servlet类配置<load-on-startup>1</load-on-startup>
当客户端请求对象的时候,不会创建Servlet类的实例化,在服务器启动的时候就已经进行了实例化,后续的对服务器的请求都是由该实例化来调用方法处理客户端的请求
- 当服务器关闭时,Servlet类的实例化就会销毁
配置load-on-startup的方式
- xml文件配置
<servlet>
<servlet-name>TestServlet</servlet-name>
<servlet-class>com.edu.servlets.TestServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>TestServlet</servlet-name>
<url-pattern>/test</url-pattern>
</servlet-mapping>
</servlet>
- 注解配置
@WebServlet(value = "/test",loadOnStartup = 1)
4.Servlet应用
4.1get和post的区别
get请求:
- get 是明文提交,提交数据量小,安全性差
- get 请求效率较高,浏览器默认的是get请求的
- get方式提交数据的场景
- 浏览器地址栏
- 网页的超链接
- form表单 method="get请求"
post请求:
- 使用POST请求服务器,参数是通过请求正文进行传递的(request body)
- POST请求是密文提交,数据量大,比较安全
- POST请求的效率较低
- Post方式提交数据的场景
- form表单 method="post请求"
4.2 request主要方法
方法名 |
说明 |
String getParameter(String name) |
根据组件名获取数据 |
void setCharacterEnconding |
指定请求的编码 |
4.3request 应用
Get请求(get请求在Tomcat8.0以上的版本是不会出现中文乱码的),post请求会出现中文乱码
需要在doPost的方法中加入req.setCharaterEncoding("utf-8")
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/demo2/rs" method="get">
用户名: <input type="text" name="username"><br>
密码: <input type="password" name="password"><br>
<input type="submit" value="注册">
</form>
</body>
</html>
@WebServlet(value="/rs")
public class RegisterServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取用户发送的数据
String username =req.getParameter("username");
String password=req.getParameter("password");
System.out.println("提交的数据"+username+"\t"+password);
}
}
4.4response对象
response用来响应客户端请求并向客户端输出信息
方法名称 |
作用 |
setHeader(name,value) |
设置响应信息头 |
setContentType(String) |
设置响应文件类型,响应式的编码格式 |
setCharavterEncoding(String) |
设置服务端响应内容的编码格式 |
getWriter() |
获取字符输出流 |
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
//1.获取用户发送的数据
String username =req.getParameter("username");
String password=req.getParameter("password");
//2.响应数据给客户端
resp.setContentType("text/html;charset=utf-8");//为了防止中文乱码,同时设置文件响应格式以及响应编码
PrintWriter printWriter=resp.getWriter();
printWriter.println("注册成功!!!");
}
5.转发和重定向
5.1.转发
转发作用在服务器端,将请求发送到服务器上的其他资源,以共同完成一次请求的处理
5.1.1页面跳转
req.getRequestDispatcher(//目标访问路径).forward(req,resp);
5.1.2数据传递
forward表示一次请求,是在服务器内部跳转,可以共享一次request作用域中的数据
- request作用域:拥有储存数据的空间,作用范围是一次请求有效(一次请求可以经过多次转发)
- 可以将数据存入request后,在一次请求过程中的任何位置进行获取
- 可传递任何数据(基本数据类型,对象,数组,集合)
- 存数据: request.setAttribute(key,value);
- 已键值对的形式存储在request作用域中.key为String类型,value为Object类型
- 取数据:request.getAttribute(key)
- 传入String类型的key得到Object类型的value
5.1.3转发特点
- 转发是服务器行为
- 转发是浏览器只做一次访问请求
- 转发浏览器地址不变
- 转发两次跳转之间传输的信息不会丢失,可以通过request进行数据的传递
- 转发只能将请求转发给同一个Web应用中的组件
5.2重定向
重定向作用于客户端,客户端向服务器端发送请求时,服务端响应一个新的请求地址给客户端,客户端重新发送新请求
5.2.1页面跳转
在调用业务逻辑的Servlet中,编写以下代码
- response.sendRedirect("目标的URL");
5.2.2数据传递
- response没有作用域,两次request请求中的数据无法共享
- 传递数据:通过URl的拼接进行数据传递
- 获取数据:request.getParameter("username");
6总结
当两个Servlet需要传递数据时,选择forward转发,不建议使用senRedirect进行传递
6 Servlet特性
6.1线程安全问题
Servlet在访问的时候,会执行实例化操作,创建一个Servlet对象.而我们Tomcat服务器的容器可以同时多个线程访问一个Servlet
在这个时候,可能会对方法中的变量进行修改,而导致其他线程出现安全问题
6.2保证线程安全
- synchronized(this){} 会造成线程缓慢,多线程会影响进度
- 实现simpleThreadModel接口 使用该接口后,每一个线程都会创建一个servlet实例,会造成资源的浪费,已经过时了
- 尽可能的使用布局变量 推荐使用
7.状态管理
7.1问题
- Http是无状态的,无法保存每次的信息结果
- 在接受新的请求时,服务器无法保证与上次连接是否有关系
- 对于需要提交多次数据的操作,服务器就会存在问题
7.2概念
将浏览器与web服务器之间多次当做一个整体来处理,并且保存多次交互的数据
7.3状态管理分类
- 客户端状态管理技术:就是用来管理客户端的状态信息,典型的有Cookie技术
- 服务器状态管理技术:将状态保证在服务器端,Session技术