Servlet
Servlet 是 Java 编程语言的一种特殊类型的类,通常用于在服务器端处理Web请求和生成Web响应。Servlet 在Java企业环境中广泛用于开发Web应用程序。
-
服务器端处理:Servlet 主要在服务器端运行,用于处理客户端发送的HTTP请求并生成响应。这使得Servlet成为构建Web应用程序的重要组件。
-
Java平台:Servlet 是基于Java平台的,因此它可以在几乎所有支持Java的服务器上运行,例如Apache Tomcat、Jetty、IBM WebSphere等。
-
生命周期:Servlet 有一个生命周期,它包括初始化、请求处理和销毁等阶段。在初始化阶段,Servlet可以执行一些初始化任务。在请求处理阶段,Servlet会响应来自客户端的HTTP请求。最后,在销毁阶段,Servlet可以执行一些清理工作。
-
HTTP请求和响应:Servlet 主要用于处理HTTP请求和生成HTTP响应。它可以接收来自浏览器的请求,读取请求参数,执行业务逻辑,然后生成HTML、XML或其他格式的响应发送回客户端。
-
灵活性:Servlet是灵活的,可以用于构建各种Web应用程序,包括动态网页、Web服务、RESTful API等。
-
Java EE(现在称为Jakarta EE):在Java企业版(Java EE)规范中,Servlet是一个重要的组成部分。Java EE定义了一整套标准API,用于构建企业级Web应用程序,Servlet就是其中之一。
Servlet的使用通常需要Java编程知识,但它是构建强大和可扩展Web应用程序的重要工具。Servlet容器(例如Tomcat)负责管理Servlet的生命周期,并确保它们可以响应来自客户端的请求。这使得Java在服务器端开发Web应用程序变得非常流行。
创建一个Servlet,实现向控制台输出字符,展示Servlet的生命周期
创建Web项目及包,创建 FirstServlet.java 。
#包名
package com.hong.Servlet.HttpServlet;
package com.hong.Servlet.HttpServlet;
import jakarta.servlet.GenericServlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @author WangYH
* @version 2021.1.3
* @date 2023/10/4 16:55
*/
public class FirstServlet extends GenericServlet {
@Override
public void init() throws ServletException {
System.out.println("init 开始运行");
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("solution Request");
//获得输出流PrintWriter对象
PrintWriter printWriter = servletResponse.getWriter();
//Servlet调用输出流对象向客户发送字符信息
printWriter.println("<h1>FirstServlet,hello</h1>");
}
@Override
public void destroy() {
System.out.println("destroy start");
}
}
第二步还要配置虚拟路径才能在浏览器访问,可以使用XML文件或者注解。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- 注册Servlet-->
<servlet>
<servlet-name> FirstServlet </servlet-name>
<servlet-class>com.hong.Servlet.HttpServlet.FirstServlet</servlet-class>
<!-- 自动加载Servlet,数字越小优先级越高-->
<load-on-startup> 1 </load-on-startup>
</servlet>
<!-- 虚拟路径配置-->
<servlet-mapping>
<servlet-name>SecondServlet</servlet-name>
<url-pattern>/SecondServlet</url-pattern>
</servlet-mapping>
</web-app>
第三步就是发布到Tomcat,输入虚拟路径访问资源。
这里主要想讲的就是,Servlet的生命周期,主要是三个方法。
- init( ),在第一次被加载的时候调用一次,可以重写方法来完成初始化。
- service( ),真正处理请求的方法,请求对象和响应对象作为其参数。
- destroy( ),清除释放**init( )**占用的资源。
配置文件写法,很重要很重要,这里没搞好,就是 404 Not Found。
第一种,xml文件配置
通常是一个名为 “web.xml” 的XML文件。在这个XML文件中,您可以定义和配置Servlet,以便在Web应用程序中使用。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- 配置一个Servlet -->
<servlet>
<servlet-name>HelloServlet</servlet-name> <!-- Servlet的名称,建议和类名一致 -->
<servlet-class>com.example.HelloServlet</servlet-class> <!-- Servlet类的完全限定名,就是包名加上类名 -->
</servlet>
<!-- 配置Servlet映射 -->
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name> <!-- 引用上面定义的Servlet名称,需要保持一致 -->
<url-pattern>/hello</url-pattern> <!-- 映射的URL路径,访问输入这段路径 -->
</servlet-mapping>
</web-app>
多重映射
在 web.xml 文件中为Servlet设置两个虚拟路径,示例代码
<!-- 配置Servlet映射 -->
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/HelloServlet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
访问 /HelloServlet
和 /hello
是一样的效果。
或者是更加简短
<!-- 配置Servlet映射 -->
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/HelloServlet</url-pattern>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
多重映射还有一个通配符知识
Servlet可以通过多重映射来处理多个不同的URL路径,这样可以将不同的请求分派到同一个Servlet或不同的Servlet上,以实现不同的处理逻辑。多重映射可以在一个Servlet应用中更灵活地处理各种请求。
以下是一些关于Servlet多重映射的示例:
-
精确匹配:您可以使用精确匹配来指定Servlet处理特定的URL路径。例如:
<servlet-mapping> <servlet-name>MyServlet</servlet-name> <url-pattern>/specific-path</url-pattern> </servlet-mapping>
在这种情况下,Servlet “MyServlet” 仅会处理 “/specific-path” 路径的请求。
-
通配符匹配:您可以使用通配符来匹配一组URL。例如:
<servlet-mapping> <servlet-name>MyServlet</servlet-name> <url-pattern>/products/*</url-pattern> </servlet-mapping>
在这种情况下,Servlet “MyServlet” 将处理以 “/products/” 开头的所有路径,例如 “/products/item1”、“/products/item2” 等。
-
扩展名匹配:您可以使用扩展名匹配来匹配特定文件扩展名的URL。例如:
<servlet-mapping> <servlet-name>ImageServlet</servlet-name> <url-pattern>*.jpg</url-pattern> </servlet-mapping>
在这种情况下,Servlet “ImageServlet” 将处理以 “.jpg” 结尾的所有URL,例如 “/images/pic1.jpg”、“/photos/photo.jpg” 等。
-
默认Servlet:在一些Servlet容器中,还有一个称为默认Servlet的特殊Servlet,它可以处理所有未匹配到其他Servlet的请求。这通常用于提供静态资源,如HTML文件、图像和CSS。
使用多重映射,您可以根据具体的需求将不同的URL请求映射到不同的Servlet上,以实现不同的处理逻辑。这允许您构建更复杂的Web应用程序,可以处理多种不同类型的请求。配置多重映射通常是在Web应用程序的"web.xml"文件中完成的。优先级原则是 精确高于模糊,路径名高于扩展名,相似度高优先。
注解配置,这个就很简短了
一般使用 "@WebServlet(name = " ", urlPatterns = {" /url "})"
,
例如上一个还可以简写成 " @WebServlet("/FirstServlet")"
还有一个是要自己配置Tomcat才行,这里就不讲了,我也是看别人教程写的。
这里特别注意一下,以下每一个示例,我都没有贴上相应的配置文件,即web.xml 是缺失的,需要自己写或者看我上面那个如何配置的那个小点,当然如果是用注解配置的话,会一并附在代码之中,就无需单独配置文件了
HttpServlet
HttpServlet类的主要方法可以查看具体源码,主要是满足不同请求方式,当然还有 service 方法。
演示一下 doGet 和 doPost 方法
package com.hong.Servlet.HttpServlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author WangYH
* @version 2021.1.3
* @date 2023/10/4 17:36
*/
public class SecondServlet extends HttpServlet {
/**
* 构造方法直接调用父类的方法
*/
public SecondServlet() {
super();
}
/**
*
* @param request 接收一个HttpServletRequest对象(用于获取请求信息)
* @param response 一个HttpServletResponse对象(用于生成响应)
* @throws ServletException
* @throws IOException
*
*/
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=GB18030");
//这一行设置响应的内容类型为"text/html;charset=GB18030",表示响应的内容将以HTML格式和GB18030字符编码发送给客户端。
response.getWriter().write("少年强则国强:A strong youth makes a strong country");
//这一行将文本消息,写入响应的输出流,以便将其发送给客户端浏览器。
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=GB18030");
response.getWriter().write("大众创业,万众创新:Mass entrepreneurship and innovation");
}
}
数据共享
web.xml 文件传递消息,ServletConfig 接口 (配置)
<servlet>
<servlet-name> FourthServlet </servlet-name>
<servlet-class>com.hong.Servlet.HttpServlet.FourthServlet</servlet-class>
<init-param>
<param-name>encoding</param-name>
<param-value>GB18030</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>FourthServlet</servlet-name>
<url-pattern>/test</url-pattern>
</servlet-mapping>
重写 doGet() 方法
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//解决中文乱码 req指的是请求
req.setCharacterEncoding("UTF-8");
//resp指的是响应
resp.setContentType("text/html");
resp.setCharacterEncoding("UTF-8");
PrintWriter writer = resp.getWriter();
//获取ServletConfig对象
ServletConfig servletConfig = this.getServletConfig();
//读取初始化参数encoding的值
String encoding = servletConfig.getInitParameter("encoding");
writer.print("参数encoding:"+encoding);
}
ServletContext (上下文)
web.xml文件
<context-param>
<param-name> username </param-name>
<param-value> admin </param-value>
</context-param>
<context-param>
<param-name>passwd</param-name>
<param-value>1234</param-value>
</context-param>
还是重写 doGet 方法
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html; charset=GB18030");
PrintWriter writer = resp.getWriter();
ServletContext context = this.getServletContext();
Enumeration<String> paramNames = context.getInitParameterNames();
while (paramNames.hasMoreElements()){
String name = paramNames.nextElement();
String value = context.getInitParameter(name);
writer.println(name + " : "+value);
writer.println("<br/>");
}
}
多个对象共享信息资源
创建三个Java文件,重写1的 doGet 方法如下
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html; charset=GB18030");
PrintWriter writer = resp.getWriter();
ServletContext context = this.getServletContext();
context.setAttribute("name", "陆亦凡");
context.setAttribute("sex","男");
String name = (String) context.getAttribute("name");
String sex = (String) context.getAttribute("sex");
writer.println("获取的上下文的name:"+name + ";\n获取的上下文的sex:"+sex);
}
重写2的 doGet 方法如下
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html; charset=GB18030");
PrintWriter writer = resp.getWriter();
ServletContext context = this.getServletContext();
context.setAttribute("name", "李萌萌");
context.setAttribute("sex","女");
String name = (String) context.getAttribute("name");
String sex = (String) context.getAttribute("sex");
writer.println("获取的上下文的name:"+name + ";\n获取的上下文的sex:"+sex);
}
重写3的 doGet 方法如下
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html; charset=GB18030");
PrintWriter writer = resp.getWriter();
ServletContext context = this.getServletContext();
String name = (String) context.getAttribute("name");
String sex = (String) context.getAttribute("sex");
writer.println("获取的上下文的name:"+name + ";\n获取的上下文的sex:"+sex);
}
访问对应的虚拟路径可看到,3会和1或者2保持一致(这里取决谁把数据存入了),这是因为name和sex属性被多个对象共享了。
读取properties文件信息内容
这里创建好properties,随便填入一些信息
username = admin;
password = 123456;
重写 doGet 方法如下
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html; charset=GB18030");
ServletContext context = this.getServletContext();
PrintWriter writer = resp.getWriter();
InputStream in = context.getResourceAsStream("/WEB-INF/classes/servuser.properties");
Properties properties = new Properties();
properties.load(in);
writer.println("获取的上下文的username:"+properties.getProperty("username"));
writer.println("<br>");
writer.println("获取的上下文的password:"+properties.getProperty("password"));
}