也就是说 servlet是一个用来处理 请求 做出回应的容器,对于每一个应用程序,Servlet容器还会创建一个ServletContext对象。这个对象中封装了上下文(应用程序)的环境详情。每个应用程序只有一个ServletContext。每个Servlet对象也都有一个封装Servlet配置的ServletConfig对象。
从Servlet3.0开始,配置Servlet支持注解方式,但还是保留了配置web.xml方式,所有使用Servlet有两
种方式:
(1)Servlet类上使用@WebServlet注解进行配置
(2)web.xml文件中配置
这个基于注解的配置关键在于@WebServlet("/hello")
这个用来设置虚拟路径然后才有了访问的地址
@WebServlet(value="/test1",loadOnStartup=1)
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.jpg</url-pattern>
</servlet-mapping>
*.do:拦截指定后缀
使用注解时,需要注意
根元素中不能配置属性metadata-complete=“true”,否则无法加载Servlet。metadata-complete属性表示通知Web容器是否寻找注解,默认不写或者设置false,容器会扫描注解,为Web应用程序构建有效的元数据;metadata-complete=“true”,会在启动时不扫描注解(annotation)。如果不扫描注解的话,用注解进行的配置就无法生效,例如:@WebServlet
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
BufferedReader in = new BufferedReader(new
InputStreamReader(request.getInputStream()));
String line = null;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
in.close();
}
@Override
protected void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
System.out.println("queryString = " + request.getQueryString());
response.getWriter().print(request.getQueryString());
}
}
<h4>get</h4>
<form action="http://localhost:8080/servlet-demo/hello" method="get">
<input type="text" name="username" value="mickey"><br>
<input type="text" name="password" value="123456"><br>
<input type="submit" value="提交">
</form>
<h4>post</h4>
<form action="http://localhost:8080/servlet-demo/hello" method="post">
<input type="text" name="username" value="mickey"><br>
<input type="text" name="password" value="123456"><br>
<input type="submit" value="提交">
</form>
这个基于XML配置的关键就在于下面图的资源路径 也就是虚拟路径 这样才可以找到这个页面
web.xml
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.lxs.demo.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
Servlet 是 Java Web 开发中的一种用于处理请求和响应的组件。它具有自己的生命周期,包括以下几个阶段:
加载:当容器启动或首次请求到达时,Servlet 容器会加载 Servlet 类。这个阶段会创建 Servlet 类的实例,并调用其 init() 方法进行初始化。
初始化:在加载后,Servlet 容器会调用 Servlet 实例的 init() 方法进行初始化。在初始化阶段,可以执行一些必要的设置,例如读取配置文件、建立数据库连接等。init() 方法在 Servlet 的生命周期中只会被调用一次。
处理请求:在初始化完成后,Servlet 容器会根据每个请求创建一个线程,调用 Servlet 实例的 service() 方法来处理请求。在 service() 方法中,可以根据请求的类型(如 GET、POST 等)执行相应的逻辑,生成响应数据。
销毁:当容器关闭或者需要卸载 Servlet 时,会调用 Servlet 实例的 destroy() 方法进行清理操作。在该方法中,可以进行资源释放、数据库连接关闭等善后工作。destroy() 方法也只会被调用一次。
需要注意的是,每次请求都会创建一个单独的线程来处理,而不是每个请求都创建一个新的 Servlet 实例。Servlet 实例是多线程共享的,因此需要在实现中保证线程安全性。
配置参数解决输出中文乱码问题
-Dfile.encoding=UTF-8 -Dconsole.encoding=UTF-8
当Servlet容器初始化Servlet时,Servlet容器会给Servlet的init( )方式传入一个ServletConfig对象。
配置参数都在web.xml里面配置
其中几个方法如下
String getServletName()
:获取当前 Servlet 的名称。
ServletContext getServletContext()
:获取与当前 Servlet 相关联的 Servlet 上下文对象。
String getInitParameter(String name)
:根据给定参数名获取相应的初始化参数值。
Enumeration
:获取所有初始化参数的名称的枚举。
总之,ServletConfig
接口提供了一种机制,允许 Servlet 访问它的配置信息和初始化参数。这些信息对于 Servlet 的运行时行为和逻辑可能会非常有用。
ServletContext
对象是 Java Web 应用程序中的一个接口,它代表了整个 Web 应用程序的上下文环境。每个 Web 应用程序只有一个 ServletContext
实例,由 Servlet 容器在启动应用程序时创建,并在关闭应用程序时销毁。
ServletContext
接口提供了一系列方法,用于访问和操作与当前 Web 应用程序相关的信息和资源,包括:
获取初始化参数:可以使用 getInitParameter(String name)
方法获取部署描述符(如 web.xml 文件)中配置的初始化参数的值。通过 getInitParameterNames()
方法可以获取所有初始化参数的名称。
获取上下文路径:可以使用 getContextPath()
方法获取当前 Web 应用程序的上下文路径(Context Path)。上下文路径是 Web 应用程序被部署后的访问路径的一部分。
获取真实路径:可以使用 getRealPath(String path)
方法将给定的相对路径转换为在文件系统中的真实路径。此方法通常用于获取在 Web 应用程序中的资源的物理路径。
获取资源:可以使用 getResource(String path)
或getResourceAsStream(String path)
方法获取位于 Web 应用程序中的某个资源的 URL 或输入流。
设置和获取属性:可以使用 setAttribute(String name, Object value)
方法设置一个在 ServletContext 中的属性。使用 getAttribute(String name)
方法可以获取指定名称的属性的值。
除了以上几点,ServletContext 还提供了其他一些方法,用于获取 Servlet 注册信息、获取和操作 ServletContext 初始化参数等。通过 ServletContext 对象,可以在整个 Web 应用程序范围内共享数据和资源,以及访问应用程序的配置信息
HttpServlet抽象类是继承于GenericServlet抽象类而来的。使用HttpServlet抽象类时,还需要借助分别代表Servlet请求和Servlet响应 HttpServletRequest和HttpServletResponse对象。
在实现这个抽象类之后我们可以通过重写Service方法来处理请求即可
HttpServlet 类定义了以下几个主要方法:
void service(HttpServletRequest request, HttpServletResponse response)
:这是 HttpServlet 的核心方法,用于处理 HTTP 请求和生成 HTTP 响应。在该方法中,可以根据不同的 HTTP 方法(如 GET、POST 等)执行相应的逻辑来处理请求的参数、生成响应内容等。
protected void doGet(HttpServletRequest request, HttpServletResponse response)
:用于处理 HTTP GET 请求的方法。默认情况下,service() 方法会调用此方法来处理 GET 请求。
protected void doPost(HttpServletRequest request, HttpServletResponse response)
:用于处理 HTTP POST 请求的方法。默认情况下,service() 方法会调用此方法来处理 POST 请求。
protected void doPut(HttpServletRequest request, HttpServletResponse response)
:用于处理 HTTP PUT 请求的方法。
protected void doDelete(HttpServletRequest request,HttpServletResponse response)
:用于处理 HTTP DELETE 请求的方法。
除了上述方法,HttpServlet 还提供了一些其他的方法,如 doOptions() 用于处理 HTTP OPTIONS 请求,doHead() 用于处理 HTTP HEAD 请求等。这些方法可以根据需要进行覆盖,以实现对不同类型的 HTTP 请求的处理
出现中文乱码问题通常就是编码和解码不一致导致
// 获取请求参数
String username = req.getParameter("username");
//1 先以 iso8859-1 进行编码
//2 再以 utf-8 进行解码
username = new String(username.getBytes("iso-8859-1"), "UTF-8");
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException,
IOException {
// 设置请求体的字符集为 UTF-8, 从而解决 post 请求的中文乱码问题
req.setCharacterEncoding("UTF-8");
System.out.println("-------------doPost------------");
// 获取请求参数
String username = req.getParameter("username");
String password = req.getParameter("password");
String[] hobby = req.getParameterValues("hobby");
System.out.println("用户名: " + username);
System.out.println("密码: " + password);
System.out.println("兴趣爱好: " + Arrays.asList(hobby));
}
// 设置服务器字符集为 UTF-8
resp.setCharacterEncoding("UTF-8");
// 通过响应头, 设置浏览器也使用 UTF-8 字符集
resp.setHeader("Content-Type", "text/html; charset=UTF-8");
解决响应中文乱码方案二(推荐) :
// 它会同时设置服务器和客户端都使用 UTF-8 字符集, 还设置了响应头
// 此方法一定要在获取流对象之前调用才有效
resp.setContentType("text/html; charset=UTF-8");
二者区别:
一次请求与两次请求!
请求转发(Request Forwarding)是一种在服务器端将请求从一个 Servlet 转发给另一个 Servlet 或 JSP 页面的机制。在请求转发中,客户端只发送一次请求,而服务器在内部将请求从一个组件传递到另一个组件,然后将响应返回给客户端。
RequestDispatcher dispatcher = request.getRequestDispatcher("/targetServlet");
其中,/targetServlet 是目标 Servlet 的路径。
dispatcher.forward(request, response);
其中,request 和 response 分别是当前 Servlet 的 HttpServletRequest 和 HttpServletResponse 对象。
请求转发的主要优点是:
请求转发通常用于以下情况:
package Servlet;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/servlet1")
public class servlet1 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username=req.getParameter("username");
System.out.println(("在Servlet1(柜台1)中查看参数(材料):"+username));
req.setAttribute("key1","柜台1的章");
RequestDispatcher requestDispatcher =
req.getRequestDispatcher("/servlet2");
requestDispatcher.forward(req,resp);
}
}
servlet2代码
package Servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/servlet2")
public class servlet2 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
System.out.println("在Servlet2(柜台2)中查看参数(材料):" + username);
// 查看 柜台1 是否有盖章
Object key1 = req.getAttribute("key1");
System.out.println("柜台1是否有章:" + key1);
// 处理自己的业务
System.out.println("Servlet2 处理自己的业务 ");
}
}
请求重定向是客户端向服务器发送请求后,服务器告诉客户端要通过新的地址进行访问的过程。这个过程中,浏览器的地址栏会发生变化,发生两次请求。与请求转发不同的是,请求重定向不能共享Request域中的数据,也不能直接访问WEB-INF下的资源,但可以访问工程外的资源。123
方式一:
// 设置响应状态码 302 , 表示重定向, (已搬迁)
resp.setStatus(302);
// 设置响应头, 说明 新的地址在哪里
resp.setHeader("Location", "http://localhost:8080");
方式二:
resp.sendRedirect("http://localhost:8080");
servlet3:
package chongdingxiang;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/servlet3")
public class servlet3 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username=req.getParameter("username");
System.out.println(("在Servlet3(柜台1)中查看参数(材料):"+username));
this.getServletContext().setAttribute("globalKey", "hello servlet global");
req.setAttribute("key3","柜台3的章");
// resp.sendRedirect("http://localhost:8080/servletdemo1/servlet4");
resp.setStatus(HttpServletResponse.SC_FOUND);
resp.setHeader("Location","http://localhost:8080/servletdemo1/servlet4");
}
}
servlet4:
package chongdingxiang;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/servlet4")
public class servlet4 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
System.out.println("在Servlet4(柜台4)中查看参数(材料):" + username);
System.out.println(this.getServletContext().getAttribute("globalKey"));
// 查看 柜台1 是否有盖章
Object key1 = req.getAttribute("key3");
System.out.println("柜台3是否有章:" + key1);
// 处理自己的业务
System.out.println("Servlet4 处理自己的业务 ");
}
}