一、servlet概述
Servlet是运行在Web服务器端的Java应用程序,它使用Java语言编写。与Java程序的区别是,Servlet 对象主要封装了对HTTP请求的处理,并且它的运行需要Servlet容器的支持。
Servlet容器
Servlet由Servlet容器提供,Servlet容器是指提供了Servlet 功能的服务器(使用Tomcat)。Servlet容器将Servlet动态地加载到服务器上。与HTTP 协议相关的Servlet使用HTTP请求和HTTP响应与客户端进行交互。因此,Servlet容器支持所有HTTP协议的请求和响应。
二、servlet接口
针对Servlet技术的开发,SUN公司提供了一系列接口和类,其中最重要的是javax.servlet.Servlet接口。Servlet就是一种实现了Servlet接口的类,它由Web容器负责创建并调用,用于接收和响应用户的请求。
2.1 servlet接口的方法
Servlet接口中有5个方法中,其中init()、service()和destroy()这三个方法可以表现Servlet的生命周期,它们会在某个特定的时刻被调用。需要注意的是,Servlet容器指的就是Web服务器。
剩下的两个方法,ServletConfig getServletConfig() 是用于获取Servlet对象的配置信息,返回Servlet的ServletConfig对象。String getServletInfo() 是用于返回一个字符串,其中包含关于Servlet的信息。
2.2 servlet 接口的实现类
servlet接口的实现类有两个,分别是GenericServlet和HttpServlet。
GenericServlet是一个抽象类,提供了部分实现,并没有实现HTTP请求处理。HttpServlet是GenericServlet的子类,它继承了GenericServlet的所有方法,并且为HTTP请求中的POST、GET等类型提供了具体的操作方法。
因此,我们在使用的时候一般直接继承HttpServlet。
2.3 第一个Servlet
创建一个Web工程项目,添加servlet相关的jar包。servlet有两种方式配置方式,一种是配置xml文件,一种是利用@WebServlet注解。
配置文件方式
在Web目录下的WEB-INF中的web.xml进行配置。
<servlet><servlet-name>ServletDemo1</servlet-name><servlet-class>com.wyy.Serv.ServletDemo1</servlet-class></servlet>
<!--映射路径--><servlet-mapping><servlet-name>ServletDemo1</servlet-name><url-pattern>/hello</url-pattern></servlet-mapping>
查找步骤
两个servlet-name一定要相同。
@WebServlet注解属性
使用:在对应的类上添加@WebServlet("填写路径")注解。填写的路径不是固定的,可自己命名。
@WebServlet("name = "HelloServlet",urlPatterns = "/HelloServlet"")
<!--这里的name等价于<servlet-name> urlPatterns指的映射路径-->
public class Servlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {super.doGet(request,response);}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.getWriter().write("Hello World");}
}
2.4 servlet生命周期
注意,在Servlet的整个生命周期内,它的init()方法只被调用一次,如果servlet已被创建,就不会再执行init()方法。对于Servlet的每一次访问请求,Servlet容器都会调用一次Servlet的service()方法,并且创建新的ServletRequest和ServletResponse对象,也就是说,service()方法在Servlet的整个生命周期中会被调用多次。
@WebServlet("/servletDemo03")
public class live extends HttpServlet {@Overridepublic void init(ServletConfig servletConfig) throws ServletException {System.out.println("初始化...");}@Overridepublic ServletConfig getServletConfig() {return null;}@Overridepublic void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {servletResponse.setContentType("text/html;charset=utf-8");PrintWriter out = servletResponse.getWriter();System.out.println("Hello Servlet");System.out.println("执行中...");}@Overridepublic String getServletInfo() {return null;}@Overridepublic void destroy() {System.out.println("被摧毁..");}
启动Tomcat服务器, 控制台信息打印。
停止服务器才servlet容器才会被摧毁。
三、ServletContext接口
当Servlet容器启动时,会为每个Web应用创建一个唯一的ServletContext对象代表当前Web应用。ServletContext对象不仅封装了当前Web应用的所有信息,而且实现了多个Servlet之间数据的共享。
ServletContext接口中定义了用于增加、删除、设置ServletContext域属性的四个方法。
3.1 设置域对象并获取
demoServlet03类中设置域对象
@WebServlet("/demoServlet03")
public class demo03GetServletContext extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//获取servletContext对象ServletContext servletContext = this.getServletContext();//设置域对象属性servletContext.setAttribute("name","zhanSan");}@Overrideprotected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {super.doPut(req, resp);}
}
demoServlet04 中获取域对象
@WebServlet("/demoServlet04")
public class demo04GetServletContext extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//获取servletContext对象ServletContext servletContext = this.getServletContext();//获取域对象属性Object name = servletContext.getAttribute("name");System.out.println(name);}@Overrideprotected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {super.doPut(req, resp);}
}
再tomcat中启用时,要先访问demoServlet03,让对象存放进去,再访问demoServlet04去获取,否则访问不到。
控制台输出
四、HttpServletResponse对象
4.1 发送状态码
当Servlet向客户端回送响应消息时,需要在响应消息中设置状态码,状态码代表着客户端请求服务器的结果。为此,HttpServletResponse接口定义了3个发送状态码的方法。
- setStatus(int status)方法用于设置HTTP响应消息的状态码,并生成响应状态行。
- sendError(int sc)方法用于发送表示错误信息的状态码
- sendError(int code, String message)方法除了设置状态码,还会向客户端发出一条错误信息。
4.2 发送Http响应头方法
设置各种头字段
- addHeader(String name, String value):设置HTTP协议的响应头字段,参数name用于指定响应头字段的名称,参数value用于指定响应头字段的值。增加同名的响应头字段
- setHeader(String name, String value):设置HTTP协议的响应头字段,参数name用于指定响应头字段的名称,参数value用于指定响应头字段的值。覆盖同名的头字段
- addIntHeader(String name, int value):设置包含整数值的响应头。
- setIntHeader(String name, int value):设置包含整数值的响应头。
设置字符编码
- setContetType():设置Servlet输出内容的MIME类型,对于HTTP协议来说,就是设置Content-Type响应头字段的值。
- setLoacale():设置响应消息的本地化信息
- setCharacterEncoding():设置输出内容使用的字符编码,对HTTP 协议来说,就是设置Content-Type头字段中的字符集编码部分。
4.3 发送响应体方法
getWriter()对应字符流输出对象
@WebServlet("/servletDemo02")
public class demo02 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {PrintWriter writer = resp.getWriter();writer.write("Hello World!");}
}
getOutputStream()对应字节输出流对象
@WebServlet("/servletDemo02")
public class demo02 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {ServletOutputStream outputStream = resp.getOutputStream();String str = "你好,世界!";
// str是字符,要先转变为字节,再可以输出outputStream.write(str.getBytes());outputStream.print("\n" + str);}
}
4.4 重定向
在某些情况下,针对客户端的请求,一个Servlet类可能无法完成全部工作。这时,可以使用请求重定向来完成。所谓请求重定向,指的是Web服务器接收到客户端的请求后,可能由于某些条件限制,不能访问当前请求URL所指向的Web资源,而是指定了一个新的资源路径,让客户端重新发送请求。
为了实现请求重定向,HttpServletResponse接口定义了一个sendRedirect()方法,该方法用于生成302响应码和Location响应头,从而通知客户端重新访问Location响应头中指定的URL。
登录案例测试重定向
准备三个页面
登录页面
注意这里的表单提交,要和下面的servlet类中的注解配置路径一样,否则无法访问。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<form action="/loginServlet" method="get">用户名:<input type="text" name="username"><br>密码:<input type="password" name="password"><br><button type="submit">登录</button>
</form>
</body>
</html>
成功页面
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<h1>登录成功</h1>
</body>
</html>
失败页面
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<h1>用户名或密码错误</h1>
</body>
</html>
创建一个servlet类
@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.setContentType("text/html;charset=utf-8");String username = req.getParameter("username");String password = req.getParameter("password");if ("admin".equals(username) && "123456".equals(password)){resp.sendRedirect("success.html");}else{resp.sendRedirect("faile.html");}}@Overrideprotected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {super.doPut(req, resp);}
}
登录成功
登录失败
五、HttpServletRequest接口
5.1 请求转发
getRequestDispatcher()方法返回封装了某条路径所指定资源的RequestDispatcher对象。其中,参数 path 必须以“/”开头,用于表示当前 Web 应用的根目录。需要注意的是,WEB-INF目录中的内容对RequestDispatcher对象也是可见的。因此,传递给 getRequestDispatcher(String path) 方法的资源可以是 WEB-INF 目录中的文件。
forward()方法用于将请求从一个 Servlet 传递给另一个 Web 资源。在 Servlet 中,可以对请求做一个初步处理,然后通过调用forward()方法,将请求传递给其他资源进行响应。需要注意的是,该方法必须在响应提交给客户端之前被调用,否则将抛出 IllegalStateException 异常。
演示
在WEB-INF目录中创建一个forward.html页面。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<h1>请求转发成功</h1>
</body>
</html>
servlet类
@WebServlet("/forwardServlet")
public class ForwardServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {RequestDispatcher requestDispatcher = req.getRequestDispatcher("/WEB-INF/forward.html");requestDispatcher.forward(req,resp);}@Overrideprotected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {super.doPut(req, resp);}
}
成功,说明可以访问到WEB-INF目录并且请求转发成功。
5.2 ServletRequest中获取请求参数的方法
- String getParameter(String name):用于获取某个指定名称的参数值
- String[] getParameterValues(String name):用于返回一个String类型的数组,HTTP请求消息中可以有多个相同名称的参数
- Enumeration getParameterNames():用于返回一个包含请求消息中所有参数名的Enumeration对象
- Map getParameterMap():用于将请求消息中的所有参数名和值装入进一个Map对象中返回
创建表单
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<!--要注意表单对应的提交路径-->
<form action="/RequestServlet03" method="get">用户名:<input type="text" name="username"><br />密 码:<input type="password" name="password"><br />爱好:<input type="checkbox" name="hobby" value="sing">唱歌<input type="checkbox" name="hobby" value="dance">跳舞<input type="checkbox" name="hobby" value="football">足球<br /><input type="submit" value="提交">
</form>
</body>
</html>
创建相关Servlet类
@WebServlet("/RequestServlet03")
public class RequestParamsServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//设置字符编码resp.setContentType("text/html;charset=utf-8");String username = req.getParameter("username");String password = req.getParameter("password");System.out.println("用户名:" + username);System.out.println("密码:" + password);String[] hobbies = req.getParameterValues("hobby");System.out.println("爱好:");for (int i = 0; i < hobbies.length; i++) {System.out.println(hobbies[i] + ",");}}@Overrideprotected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {super.doPut(req, resp);}
}
在表单页面进行输入
结果
5.3 通过Request对象传递数据
setAttribute()方法的参数列表的第一个参数接收的是一个String类型的name,第二个参数接收的是一个Object类型的对象。如果ServletRequest对象中已经存在指定名称的属性,setAttribute()方法将会先删除原来的属性,然后再添加新的属性。如果传递给setAttribute()方法的属性值对象为null,则删除指定名称的属性,这时的效果等同于removeAttribute()方法。
getAttributeNames()方法:用于返回一个包含ServletRequest对象中的所有属性名的Enumeration对象。需要注意的是,只有属于同一个请求中的数据才可以通过ServletRequest对象传递数据。