Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态Web内容,它是由Sun公司(现在是Oracle公司)开发的,作为Java Servlet API的一部分,包含在Java EE(Enterprise Edition)规范中
狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,将Servlet理解为后者。Servlet运行于支持Java的应用服务器中。从原理上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。
servlet-api.jar
并不包含在我们安装的JDK(Java SE)中,它是Java EE规范的一部分,通常作为Web容器(如Tomcat、Jetty、WebLogic等)的一部分提供。
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
如果您想要使用servlet-api.jar
来编写servlet应用程序,您可以通过以下途径获取:
下载并安装一个Java Web容器,如Apache Tomcat。然后在Tomcat
安装目录下的lib
文件夹中找到servlet-api.jar
。
下载Java EE,其中包括Servlet API的实现,并在安装目录下的lib文件夹中找到servlet-api.jar
(Oracle已经不提供Java EE的下载了)
servlet-api.jar
只是在编译的时候需要,运行的时候使用Web容器内置的即可,所以不必打包进项目依赖,以免发生冲突,使用maven可以声明scope
为provided
注意:由于Java EE被Orcale捐献给Apache,并且在2021年更名为Jakarta EE,所以从 Jakarta EE 9 开始对应用的Servlet类名是:jakarta.servlet.Servlet
,而之前是javax.servlet.Servlet
,所以如果之前的项目还在使用javax.servlet.Servlet
,那么你的项目无法直接部署到Tomcat10+
版本上。你只能部署到Tomcat9-
版本上。在Tomcat9以及Tomcat9之前的版本中还是能够识别javax.servlet
这个包。
Servlet程序、Filter过滤器、Listener监听器
javax.servlet.Servlet
(接口):是所有Servlet类的父接口,它定义了Servlet必须实现的方法,包括init()
、service()
和destroy()
等javax.servlet.ServletConfig
(接口):代表着Servlet的配置信息,例如初始化参数、Servlet名称等。在Servlet的生命周期中,容器会调用其init()
方法,并传递一个ServletConfig对象作为参数。
javax.servlet.GenericServlet
(抽象类):实现了Servlet、ServletConfig接口。它提供了一些通用的方法,例如getServletConfig()
、getInitParameter()
等。通过继承GenericServlet可以简化自定义Servlet的编程,因为只需要实现其中的service()
方法即可。
javax.servlet.http.HttpServlet
(类):是GenericServlet的子类,并实现了HttpServletRequest和HttpServletResponse接口。它针对HTTP协议提供了更加方便的处理方式,例如doGet()
、doPost()
等方法。通过继承HttpServlet,开发人员可以方便地处理HTTP请求和响应void init(ServletConfig config)
:由Servlet容器调用,用于初始化Servlet对象void service(ServletRequest req,ServletResponse res)
:由Servlet容器调用,用于处理客户端请求并响应void destory()
:由Servlet容器调用,释放Servlet对象所使用的资源ServletConfig getServletConfig()
:返回ServletConfig对象String getServletInfo()
:返回关于Servlet的信息,比如作者、版本、版权service()
、doGet()
、doPost()
均是Java Servlet中的方法,但是它们在处理请求时有所不同。
service()
方法是Servlet执行请求的主要方法,当客户端发出请求时,Servlet容器将调用service()
方法来处理请求并生成响应。这个方法根据具体的HTTP请求类型(GET、POST、PUT、DELETE等)来决定调用哪个子方法进行处理。
doGet()
方法处理HTTP GET请求,通常用于获取信息或数据,并且参数会显示在URL中,它不会修改服务器上的任何数据。
doPost()
方法处理HTTP POST请求,通常用于向服务器提交数据,并且请求参数在请求体内。它可以对服务器上的数据进行更改。
总结:service()
方法是Servlet处理请求的主要方法,而doGet()
和doPost()
方法是service()
方法的具体实现,用于处理GET和POST请求。同时出现的情况下,service()
优先。
1、定义一个类,去实现javax.servlet.Servlet
接口
2、定义一个类,去继承javax.servlet.GenericServlet
抽象类
3、定义一个类,去继承javax.servlet.http.HttpServlet
抽象类(推荐)
//注意:如果一个Servlet类,三个方法一个都没有重写,请求时会报405
class MyServlet extends HttpServlet {
doGet() {}
doPost() {}
service() {}
}
<servlet>
<servlet-name>名称1</servlet-name>
<servlet-class>Servlet全类名(包+类)</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>名称1</servlet-name>
<url-pattern>/虚拟路径</url-pattern>
</servlet-mapping>
@WebServlet
:属于类级别的注解,标注在继承了 HttpServlet 的类之上。常用的写法是将 Servlet 的相对请求路径(即 value)直接写在注解内name
-String
:指定Servlet的名称,如果没有指定,默认是Servlet类的全类名value
-String[]
:完全等价于urlPatterns
属性,二者不能同时指定urlPatterns
-String[]
:指定一组Servlet的匹配路径loadOnStartup
-int
:指定Servlet的加载顺序initParams
-WebInitParam
:指定Servlet的启动参数asyncSupported
-boolean
:Servlet是否支持异步操作模式description
-String
:Servlet的描述displayName
-String
:Servlet的显示名在继承了Servlet类上方,添加注解,用于配置此Servlet的虚拟地址,三种方法
@WebServlet(value="/servletDemo1")
public MyServle extends HttpServlet{}
@WebServlet(value={"/servletDemo1","/servletDemo2"})
public MyServle extends HttpServlet{}
@WebServlet({"/servletDemo1","/servletDemo2"})
public MyServle extends HttpServlet{}
@WebServlet(urlPatterns="/servletDemo1")
public MyServle extends HttpServlet{}
http://localhost:8080/项目虚拟目录/servlet虚拟路径
在JavaWeb中,Servlet中三大域对象分别是request,session,ServletContext,其只要是用来存放共享数据的。
之所以他们是域对象,原因是他们都内置了Map
集合,都有setAttribute
、getAttribute
和removeAttribute
方法用于操作值。
只要是域对象,都有这3个方法,可以实现数据共享,都是以key-value方式存放数据,key必须是String类型,value是Object类型
名称 | 对象类型 | 作用域 | 说明 |
---|---|---|---|
application | ServletContext | 在整个应用程序中有效 | 通过request.getServletContext() 方法获取,可以在整个应用范围内共享数据 |
session | HttpSession | 在当前会话中有效 | 通过request.getSession() 获取,会话代表同一浏览器向服务器的多次请求和响应 |
request | HttpServletRequest | 在当前请求中有效 | 在一次请求的范围内,可以共享资源 |
page | PageContext | JSP的请求到响应中有效 | 作用范围是当前用户请求的JSP页面渲染时,一旦渲染结束响应即失效 |
servlet的生命周期是由三个方法体现的,称为生命周期方法:
init()
:初始化方法,只有在首次访问时调用service()
:执行方法,每次访问,都会调用destroy()
:销毁方法,只有Servlet销毁时调用(WEB工程停止时)1、当我们第一次访问servlet的时候,会创建servlet对象(调用构造器),调用servlet的init()
,然后调用service()
2、当我们再一次访问servlet的时候,就不会调用init()
,只会调用service()
3、当我们正常关闭服务器的时候,会调用servlet的destroy()
String getMethod()
:获取请求方式String getContextPath()
:获取项目的虚拟目录String getServletPath()
:获取servlet的虚拟路径String getQueryString()
:获取get请求的请求参数String getRequestURI()
:获取请求的URI(资源路径)StringBuffer getRequestURL()
:获取请求的URL(绝对路径)String getProtocol()
:获取协议/版本号String getRemoteAddr()
:获取客户端的IP地址path?k1=v1&k2=v2
获取这种形式的参数
String getParameter(String name)
:根据请求参数的名称获取值Enumeration<String> getParameterNames()
:获取所有的请求参数的名称String[] getParameterValues(String name)
:根据请求参数的名称获取值(多个)Map<String,String[]> getParameterMap()
:将所有请求参数的名称和值都封装到了map对象String getHeader(String name)
:根据请求头的名称获取请求头的值Enumeration<String> getHeaderNames()
:获取所有的请求头的名称Enumeration<String> getHeaders(String name)
:根据请求头的名称获取多个请求头的值int getIntHeader(String name)
:根据请求头的名称获取请求头的值(请求头值为int类型的时候)BufferedReader getReader()
:获取ReaderServletInputStream getInputStream()
:获取InputStreamvoid setStatus(int sc)
void setHeader(String name, String value)
打印流:PrintWriter getWriter()
字节流:ServletOutputStream getOutputStream()
//将tomcat写出的编码由ISO-8859-1变成UTF-8
response.setCharacterEncoding("utf-8");
//上述方法,只会将服务器写出的编码为utf-8,所以,需要服务器告诉浏览器使用utf-8来打开
//推荐!!!
response.setHeader("Content-Type", "text/html;charset=utf-8");
//或
response.setContentType("text/html;charset=utf-8");
可以通过Response实例的getOutPutStream()
向浏览器进行响应,例如响应html文件
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取请求体中的参数,和数据库进比较
String name = req.getParameter("name");
String psw = req.getParameter("psw");
SqlSession sqlSession = MyBatisUtil.getSqlSession();
UsersDao usersDao = sqlSession.getMapper(UsersDao.class);
Users byNameAndPsw = usersDao.findByNameAndPsw(name, psw);
//获取当前项目路径
String contextPath = req.getServletContext().getRealPath("/");
//登录成功、失败不同的html页面
String path = null;
if (byNameAndPsw == null){
path = "fail.html";
}else {
path = "success.html";
}
//获得对应页面的输入流
InputStream inputStream = new FileInputStream(contextPath + path);
//获得输出流
ServletOutputStream outputStream = resp.getOutputStream();
//将输入流的内容,写出到输出流
byte[] bytes = new byte[1024];
int len = 0;
while ( (len = inputStream.read(bytes)) >0 ){
outputStream.write(bytes,0,len);
}
//关闭资源
outputStream.flush();
outputStream.close();
inputStream.close();
}
1、通过注解或xml文件设置该url的多个URL,例如
@WebServlet(value={"goodsType/add","goodsType/change"})
2、通过request对象的getRequestURI()
方法,获取该请求的URI(如shop/goodsType/add
),然后通过字符串的分割,获取具体的请求
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//解析请求的方法
String uri = req.getRequestURI();
String resUri = uri.substring(uri.lastIndexOf("/") + 1);
//根据请求类型,使用反射获取并执行对应的方法
Method method = null;
try {
method = this.getClass().getMethod(resUri, HttpServletRequest.class, HttpServletResponse.class);
method.setAccessible(true);
method.invoke(this,req,resp);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
public void add(HttpServletRequest req, HttpServletResponse resp){
}
public void change(HttpServletRequest req, HttpServletResponse resp){
}
无论转发还是重定向,始终都是请求一次,响应一次
调用服务端的资源(静态、动态)
request.getRequestDispatcher("/path").forward(request,response);
属于一次请求
响应头没有Location
可以在request范围内共享数据
只可以使用本应用的资源
地址栏不会发生变化,就是请求时的地址
重新定位一下,通过响应头中的Location,告诉浏览器,需要重新请求一次
response.sendRedirect();
两次请求
第一次的请求中,响应头有Location
无法在request范围内共享数据,可以通过session或者application(ServletContext)达到数据的共享
可以调用应用之外的资源
地址栏会发生变化,就是最后请求地址