前情回顾

1、Servlet概念及特点

2、Servlet接口及实现类使用

3、Servlet配置

4、Servlet生命周期

今日内容

  • ServletConfig
  • ServletContext
  • web服务器Tomcat
  • eclipse+tomcat配置
  • JavaEE项目创建与发布

ServletConfig接口

在Servlet运行期间,经常需要一些配置信息,例如,文件使用的编码等,这些信息都可以在web.xml 或 @WebServlet注解的属性中配置。当Tomcat初始化一个Servlet时,会将该Servlet的配置信息封装到一个ServletConfig对象中每一个servlet都有一个ServletConfig对象。通过调用init(ServletConfig config)方法将ServletConfig对象传递给Servlet。ServletConfig定义了一系列获取配置信息的方法
image.png

  1. <servlet>
  2. <servlet-name>TestServlet02</servlet-name>
  3. <servlet-class>com.gmxy.www.TestServlet02</servlet-class>
  4. <init-param>
  5. <param-name>encoding</param-name>
  6. <param-value>UTF-8</param-value>
  7. </init-param>
  8. </servlet>
  9. <servlet-mapping>
  10. <servlet-name>TestServlet02</servlet-name>
  11. <url-pattern>/TestServlet02</url-pattern>
  12. </servlet-mapping>
  1. //省略其他
  2. protected void doGet(HttpServletRequest request,
  3. HttpServletResponse response) throws ServletException, IOException {
  4. PrintWriter out = response.getWriter();
  5. //1.获得ServletConfig对象
  6. ServletConfig config = this.getServletConfig();
  7. //2.获取Servlet的名称
  8. String servletName= servletConfig.getServletName();
  9. System.out.println(servletName);
  10. //3.获得 参数名 为encoding 对应的参数值
  11. String param = config.getInitParameter("encoding");
  12. out.println("encoding=" + param);
  13. //4.获取所有初始化参数名称的枚举
  14. Enumeration<String> names = config.getInitParameterNames();
  15. //遍历names
  16. while(names.hasMoreElements()){
  17. //取出每个name
  18. String name = names.nextElement();
  19. //根据key获取value
  20. String value = config.getInitParameter(name);
  21. System.out.println("name:"+name+",value:"+value);
  22. }
  23. //5.获取ServletContext对象
  24. ServletContext servletContext = config.getServletContext();
  25. System.out.println(servletContext);
  26. }

ServletContext接口

当Servlet容器启动时,会为每个Web应用创建一个唯一的ServletContext对象表当前Web应用(一个Web应用共享这个ServletContext对象),该对象包含了当前Web应用的所有信息,而且实现了多个Servlet之间数据的共享
常用如下:

1. 获取Web应用程序的全局初始化参数

web.xml文件中,可以配置Servlet的初始化信息,还可以配置整个Web应用的初始化信息。Web应用初始化参数的配置方式具体如下所示。

  1. <!--省略其他-->
  2. <web-app>
  3. <servlet>
  4. ...
  5. </servlet>
  6. <!--全局配置,跟 servlet标签并列-->
  7. <context-param>
  8. <param-name>companyName</param-name>
  9. <param-value>w3c</param-value>
  10. </context-param>
  11. <context-param>
  12. <param-name>address</param-name>
  13. <param-value>beijing</param-value>
  14. </context-param>
  15. <servlet>
  16. ...
  17. </servlet>
  18. </web-app>

元素位于根元素中,它的子元素分别用来指定参数的名字和参数值。
通过调用ServletContext接口中定义的getInitParameterNames()和getInitParameter(String name)方法,分别获取参数名和参数值。

  1. public class TestServlet04 extends HttpServlet {
  2. public void doGet(HttpServletRequest request,
  3. HttpServletResponse response)throws ServletException, IOException {
  4. response.setContentType("text/html;charset=utf-8");
  5. PrintWriter out = response.getWriter();
  6. //获取ServletContext对象
  7. ServletContext context = this.getServletContext();
  8. //得到 所有 初始化参数名的 Enumeration对象
  9. Enumeration<String> paramNames = context.getInitParameterNames();
  10. out.println("all the paramName and paramValue are following:");
  11. while (paramNames.hasMoreElements()) {
  12. String name = paramNames.nextElement(); //获取枚举值
  13. //获取参数值
  14. String value = context.getInitParameter(name);
  15. out.println(name + ":" + value);
  16. out.println("<br />");
  17. }
  18. }

2. 多个Servlet共享数据

一个Web应用的所有Servlet共享同一个ServletContext对象,所以ServletContext对象的域属性可以被该Web应用中的所有Servlet访问。ServletContext接口中定义了用于增加、删除、设置ServletContext域属性的四个方法
ServletContext.png
image.png

实例:通过 ServletContext 中的方法,实现2个Servlet之间共享数据。

创建TestServlet05类,调用了ServletContext接口中的方法,设置一个值。

  1. public class TestServlet05 extends HttpServlet {
  2. public void doGet(HttpServletRequest request,
  3. HttpServletResponse response)throws ServletException, IOException {
  4. ServletContext context = this.getServletContext();
  5. // 通过setAttribute()方法设置属性值
  6. context.setAttribute("data", "this servlet save data");
  7. }
  8. public void doPost(HttpServletRequest request,
  9. HttpServletResponse response)throws ServletException, IOException {
  10. this.doGet(request, response);
  11. }
  12. }

创建TestServlet06类,在该Servlet类中调用了ServletContext接口中的方法获取属性值。

  1. public class TestServlet06 extends HttpServlet {
  2. public void doGet(HttpServletRequest request,
  3. HttpServletResponse response)throws ServletException,IOException{
  4. PrintWriter out = response.getWriter();
  5. ServletContext context = this.getServletContext();
  6. // 通过getAttribute()方法获取属性值
  7. String data = (String)context.getAttribute("data");
  8. out.println(data);
  9. }
  10. public void doPost(HttpServletRequest request,
  11. HttpServletResponse response)throws ServletException,IOException{
  12. this.doGet(request,response);
  13. }
  14. }

3.其他常用方法

  1. //获取ServletContext对象
  2. ServletContext context = getServletContext();
  3. //获取应用的访问虚拟目录
  4. String contextPath = context.getContextPath();
  5. System.out.println(contextPath);
  6. //根据虚拟目录获取应用部署的磁盘绝对路径
  7. //获取a.txt文件的绝对路径
  8. String a = context.getRealPath("/a.txt");
  9. System.out.println(a);

HttpServletResponse对象

状态码方法

当Servlet向客户端回送响应消息时,需要在响应消息中设置状态码,状态码代表着客户端请求服务器的结果。为此,HttpServletResponse接口定义了3个发送状态码的方法。

setStatus(int status)方法
于设置HTTP响应消息的状态码,并生成响应状态行。由于响应状态行中的状态描述信息直接与状态码相关,而HTTP版本由服务器确定,所以,只要通过setStatus(int status)方法设置了状态码,即可实现状态行的发送。例如,正常情况下,Web服务器会默认产生一个状态码为200的状态行。

sendError(int sc)方法
用于发送表示错误信息的状态码,例如,404状态码表示找不到客户端请求的资源。

sendError(int code, String message)方法
除了设置状态码还会向客户端发出一条错误信息。服务器默认会创建一个HTML格式的错误服务页面作为响应结果,其中包含参数message指定的文本信息,这个HTML页面的内容类型为“text/html”,保留cookies和其他未修改的响应头信息。如果一个对应于传入的错误码的错误页面已经在web.xml中声明,那么这个声明的错误页面会将优先建议的message参数服务于客户端。

响应消息头相关的方法

image.png

设置HTTP响应头字段的方法

image.png

实例: 设置消息头,实现定时刷新

  1. public void doGet(HttpServletRequest request, HttpServletResponse response)
  2. throws ServletException, IOException {
  3. String str = "用户名和密码不匹配,2秒后转向登录页面...";
  4. response.setContentType("text/html;charset=UTF-8");
  5. PrintWriter out = response.getWriter();
  6. out.write(str);
  7. //定时刷新,其实就是设置一个响应消息头
  8. response.setHeader("Refresh", "2;URL=/login.html");
  9. //Refresh设置的时间单位是秒,如果刷新到其他地址,需要在时间后面拼接上地址
  10. }

小结
addHeader()、setHeader()、addIntHeader()、setIntHeader()方法都是用于设置各种头字段的,而setContetType()、setLoacale()和setCharacterEncoding()方法用于设置字符编码,这些设置字符编码的方法可以有效解决中文字符乱码问题。

响应消息体相关的方法

在HTTP响应消息中,大量的数据都是通过响应消息体传递的,所以,ServletResponse遵循IO流传递大量数据的设计理念。在发送响应消息体时,定义了两个输出流相关的方法

1、getOutputStream()方法
image.png

  1. //以二进制 字节流 方式 响应应数据
  2. public class PrintServlet extends HttpServlet {
  3. public void doGet(HttpServletRequest request,
  4. HttpServletResponse response)throws ServletException, IOException {
  5. String data = "response data";
  6. // 获取字节输出流对象
  7. OutputStream out = response.getOutputStream();
  8. out.write(data.getBytes());// 输出信息
  9. }
  10. }

2、getWriter()方法
PrintWriter 类中的 getWriter()方法,获取字符输出流对象。由于PrintWriter类型的对象可以直接输出字符文本内容,所以,要想输出内容为字符文本的网页文档,需要调用getWriter()方法。

  1. public class PrintServlet extends HttpServlet {
  2. public void doGet(HttpServletRequest request,
  3. HttpServletResponse response)throws ServletException, IOException {
  4. String data = "response data";
  5. // 获取字节输出流对象
  6. OutputStream out = response.getOutputStream();
  7. out.write(data.getBytes());// 输出信息
  8. }
  9. }

请求重定向-sendRedirect()

在某些情况下,针对客户端的请求,一个Servlet类可能无法完成全部工作。这时,可以使用请求重定向来完成。所谓请求重定向,指的是Web服务器接收到客户端的请求后,可能由于某些条件限制,不能访问当前请求URL所指向的Web资源,而是指定了一个新的资源路径,**

sendRedirect()方法用于生成302响应码和Location响应头,从而通知客户端重新访问Location响应头中指定的URL。两次请求,地址栏改变,浏览器行为.

sendRedirect()方法的完整声明如下:

  1. public void sendRedirect(java.lang.String location) throws java.io.IOException

注意:参数location可以使用相对URL,Web服务器会自动将相对URL翻译成绝对URL,再生成Location头字段。

原理:
image.png

实例:用户登录,用户名“javaweb”,密码“12345”
image.png
image.png

  1. //登录:login.html
  2. <!--把表单内容提交到chapter04工程下的LoginServlet-->
  3. <form action="/web/LoginServlet" method="post">
  4. 用户名: <input type="text" name="username" /><br />
  5. 密&nbsp;&nbsp;&nbsp;码:<input type="password" name="password"/><br />
  6. <input type="submit" value="登录" />
  7. </form>
  8. //登录处理:LoginServlet.java
  9. public void doGet(HttpServletRequest request,
  10. HttpServletResponse response)throws ServletException, IOException {
  11. response.setContentType("text/html;charset=utf-8");
  12. // 用HttpServletRequest对象的getParameter()方法获取用户名和密码
  13. String username = request.getParameter("username");
  14. String password = request.getParameter("password");
  15. //比较用户名,密码
  16. if (("javaweb").equals(username) &&("12345").equals(password)) {
  17. //登录成功,到欢迎页
  18. response.sendRedirect("welcome.html");
  19. } else {
  20. response.sendRedirect("login.html");
  21. }
  22. }
  23. //登录成功:welcome.html
  24. <body>
  25. 欢迎你,登录成功!
  26. </body>

输出中文乱码问题

由于计算机中的数据都是以二进制形式存储的,所以,当传输文本时,就会发生字符和字节之间的转换。字符与字节之间转换是通过查码表完成的,将字符转换成字节的过程称为编码,将字节转换成字符的过程称为解码,如果编码和解码使用的码表不一致,就会导致乱码问题。

  1. public void doGet(HttpServletRequest request,
  2. HttpServletResponse response)throws ServletException, IOException {
  3. String data = "中国";
  4. PrintWriter out = response.getWriter();
  5. out.println(data);
  6. }

image.png
image.png
推荐使用第二种

  1. public void doGet(HttpServletRequest request,
  2. HttpServletResponse response) throws ServletException, IOException {
  3. //设置 响应 字符编码,解决 输出中文 乱码问题
  4. response.setContentType("text/html;charset=utf-8");
  5. String data="中国";
  6. PrintWriter out = response.getWriter();
  7. out.println(data);
  8. }

HttpServletRequest对象

对于 HttpServletRequest 对象(以下简称 request 对象),我们并不陌生,在之前的 service、doGet或是 doPost 方法中它都出现过,接下来我们来讲解这个 request 对象。

请求对象,就是在JavaEE工程中,用于发送请求的对象。我们常用的对象就是ServletRequest和HttpServletRequest,它们的区别就是是否和HTTP协议有关。

HTTP 中的请求报文是有很多请求信息的,包括请求头、请求行等。当请求报文到达 Tomcat 服务器后,服务器就要对这些信息进行解析和保存。而 request 对象最主要的作用就是用来保存 HTTP 请求报文里面的信息开发人员通过这个对象的方法,可以获得客户的一些信息。request 对象是由服务器创建的,在一个请求处理完成之后它所保存的信息也就没有意义了,所以它的生命周期是一个请求内。值得注意的是,服务器每接收到一个请求,就会创建一个 request 对象来保存这些请求信息。

request对象常用方法.

1、获取请求行的相关方法

image.png
image.png

常用:getRemoteAddr、getMethod、getContextPath、getServletName、getServletPath

举例:请求对象的各种信息获取

  1. public void doGet(HttpServletRequest request, HttpServletResponse response)
  2. throws ServletException, IOException {
  3. //本机地址:服务器地址
  4. String localAddr = request.getLocalAddr();
  5. //本机名称:服务器名称
  6. String localName = request.getLocalName();
  7. //本机端口:服务器端口
  8. int localPort = request.getLocalPort();
  9. //来访者ip
  10. String remoteAddr = request.getRemoteAddr();
  11. //来访者主机
  12. String remoteHost = request.getRemoteHost();
  13. //来访者端口
  14. int remotePort = request.getRemotePort();
  15. //统一资源标识符
  16. String URI = request.getRequestURI();
  17. //统一资源定位符
  18. String URL = request.getRequestURL().toString();
  19. //获取查询字符串
  20. String queryString = request.getQueryString();
  21. //获取Servlet映射路径
  22. String servletPath = request.getServletPath();
  23. //输出内容
  24. System.out.println("getLocalAddr() is :"+localAddr);
  25. System.out.println("getLocalName() is :"+localName);
  26. System.out.println("getLocalPort() is :"+localPort);
  27. System.out.println("getRemoteAddr() is :"+remoteAddr);
  28. System.out.println("getRemoteHost() is :"+remoteHost);
  29. System.out.println("getRemotePort() is :"+remotePort);
  30. System.out.println("getRequestURI() is :"+URI);
  31. System.out.println("getRequestURL() is :"+URL);
  32. System.out.println("getQueryString() is :"+queryString);
  33. System.out.println("getServletPath() is :"+servletPath);
  34. }

举例:获取请求消息头

  1. public void doGet(HttpServletRequest request, HttpServletResponse response)
  2. throws ServletException, IOException {
  3. //1.根据名称获取头的值 一个消息头一个值
  4. String value = request.getHeader("Accept-Encoding");
  5. System.out.println("getHeader():"+value);
  6. //2.根据名称获取头的值 一个头多个值
  7. Enumeration<String> values = request.getHeaders("Accept");
  8. while(values.hasMoreElements()){
  9. System.out.println("getHeaders():"+values.nextElement());
  10. }
  11. //3.获取请求消息头的名称的枚举
  12. Enumeration<String> names = request.getHeaderNames();
  13. while(names.hasMoreElements()){
  14. String name = names.nextElement();
  15. String value1 = request.getHeader(name);
  16. System.out.println(name+":"+value1);
  17. }
  18. }

2、获取请求参数

获取客端向服务端请求时候携带的数据。
image.png

准备一个表单

  1. <form action="/day/RequestDemo3" method="post">
  2. 用户名:<input type="text" name="username" /><br/>
  3. 密码:<input type="password" name="password" /><br/>
  4. 性别:<input type="radio" name="gender" value="1" checked>
  5. <input type="radio" name="gender" value="0">
  6. <br/>
  7. <input type="submit" value="注册" />
  8. </form>

RequestParamsServlet的Servlet类,使用该Servlet获取请求参数。

  1. public void doGet(HttpServletRequest request,
  2. HttpServletResponse response)throws ServletException, IOException {
  3. //单个值
  4. String name = request.getParameter("username");
  5. String password = request.getParameter("password");
  6. System.out.println("用户名:" + name);
  7. System.out.println("密 码:" + password);
  8. // 获取参数名为“hobby”的值,复选框,是一个数组(多个值)
  9. String[] hobbys = request.getParameterValues("hobby");
  10. System.out.print("爱好:");
  11. for (int i = 0; i < hobbys.length; i++) {
  12. System.out.print(hobbys[i] + ", ");
  13. }
  14. }

3、通过Request对象传递数据

Request对象是4大域对象之一,可以通过Request对象来保存数据,在当前请求这个生命周期内都有效,可以用来传递数据。

public void setAttribute(String name,Object o);
setAttribute()方法的参数列表的第一个参数接收的是一个String类型的name第二个参数接收的是一个Object类型的对象o。在请求域中保存一个数据
需要注意的是,如果ServletRequest对象中已经存在指定名称的属性,setAttribute()方法将会先删除原来的属性,然后再添加新的属性。如果传递给setAttribute()方法的属性值对象为null,则删除指定名称的属性,这时的效果等同于removeAttribute()方法。

public Object getAttribute(String name); 从ServletRequest对象中返回指定名称的属性对象。
public void removeAttribute(String name); 从ServletRequest对象中删除指定名称的属性
public Enumeration getAttributeNames(); 返回一个包含ServletRequest对象中的所有属性名的Enumeration对象,在此基础上,可以对ServletRequest对象中的所有属性进行遍历处理,从而获取属性名称对应的值。

4、请求参数的中文乱码问题

  1. 1. post方式

request.setCharacterEncoding(“GBK”);

  1. public void doGet(HttpServletRequest request, HttpServletResponse response)
  2. throws ServletException, IOException {
  3. //设置请求时编码
  4. request.setCharacterEncoding("UTF-8");
  5. String username = request.getParameter("username");
  6. //输出到控制台
  7. System.out.println(username);
  8. //输出到浏览器:注意响应的乱码问题已经解决了
  9. response.setContentType("text/html;charset=UTF-8");
  10. PrintWriter out = response.getWriter();
  11. out.write(username);
  12. }
  1. 2. get方式

GET方式请求的正文是在地址栏中,在Tomcat8.5版本及以后,Tomcat服务器已经帮我们解决了,所以不会有乱码问题了。如果我们使用的不是Tomcat服务器,或者Tomcat的版本是8.5以前,那么GET方式仍然会有乱码问题,解决方式如下:(以下代码了解即可,因为我们现在使用的是Tomcat9.0.27版本)

  1. public void doGet(HttpServletRequest request, HttpServletResponse response)
  2. throws ServletException, IOException {
  3. /*
  4. * GET方式:正文在地址栏
  5. * username=%D5%C5%C8%FD
  6. * %D5%C5%C8%FD是已经被编过一次码了
  7. *
  8. * 解决办法:
  9. * 1.使用正确的码表对已经编过码的数据进行解码。
  10. * 就是把取出的内容转成一个字节数组,但是要使用正确的码表。(ISO-8859-1)
  11. * 2.再使用正确的码表进行编码
  12. * 把字节数组再转成一个字符串,需要使用正确的码表,是看浏览器当时用的是什么码表
  13. */
  14. String username = request.getParameter("username");
  15. byte[] by = username.getBytes("ISO-8859-1");
  16. username = new String(by,"UTF-8");
  17. //输出到浏览器:注意响应的乱码问题已经解决了
  18. response.setContentType("text/html;charset=UTF-8");
  19. PrintWriter out = response.getWriter();
  20. out.write(username);
  21. }

5、请求转发与包含

请求转发

Servlet之间可以相互跳转,利用Servlet的跳转可以很容易地把一项任务按模块分开,例如,使用一个Servlet实现用户登录,然后跳转到另外一个Servlet实现用户资料修改。

Servlet的跳转要通过RequestDispatcher接口的实例对象实现。HttpServletRequest接口提供了getRequestDispatcher()方法用于获取RequestDispatcher对象,getRequestDispatcher()方法的具体格式如下所示。

实现
1、获取RequestDispatcher对象
RequestDispatcher getRequestDispatcher(String path);
getRequestDispatcher()方法返回封装了某条路径所指定资源的RequestDispatcher对象。其中,参数 path 必须以“/”开头,用于表示当前 Web 应用的根目录。

  1. RequestDispatcher dispatcher = getRequestDispatcher("/abc");

2、调用forward(req,res)方法

  1. dispatcher.forwrad(req,res);

实例:/RequestDemo7 转发到 /RequestDemo8

  1. /**
  2. * 重定向特点:
  3. * 两次请求,浏览器行为,地址栏改变,请求域中的数据会丢失
  4. * 请求转发:
  5. * 一次请求,服务器行为,地址栏不变,请求域中的数据不丢失
  6. *
  7. * 请求域的作用范围:
  8. * 当前请求(一次请求),和当前请求的转发之中
  9. */
  10. //转发开始
  11. public class RequestDemo6 extends HttpServlet {
  12. public void doGet(HttpServletRequest request, HttpServletResponse response)
  13. throws ServletException, IOException {
  14. //1.拿到请求调度对象
  15. RequestDispatcher rd = request.getRequestDispatcher("/RequestDemo7");//如果是给浏览器看的,/可写可不写。如果是给服务器看的,一般情况下,/都是必须的。
  16. //放入数据到请求域中
  17. request.setAttribute("CityCode", "bj-010");
  18. //2.实现真正的转发操作
  19. rd.forward(request, response);//实现真正的转发操作
  20. }
  21. public void doPost(HttpServletRequest request, HttpServletResponse response)
  22. throws ServletException, IOException {
  23. doGet(request, response);
  24. }
  25. }
  26. /**
  27. * 转发的目的地
  28. */
  29. public class RequestDemo7 extends HttpServlet {
  30. public void doGet(HttpServletRequest request, HttpServletResponse response)
  31. throws ServletException, IOException {
  32. //获取请求域中的数据
  33. String value = (String)request.getAttribute("CityCode");
  34. response.getWriter().write("welcome to request demo 7 "+value);
  35. }
  36. public void doPost(HttpServletRequest request, HttpServletResponse response)
  37. throws ServletException, IOException {
  38. doGet(request, response);
  39. }
  40. }

请求包含

把两个Servlet的内容合并到一起响应浏览器,而同学们都知道HTTP协议的特点是一请求,一响应的方式。所以绝对不可能出现有两个Servlet同时响应方式。那么我们就需要用到请求包含,把两个Servlet的响应内容合并输出

  1. /**
  2. * 请求包含
  3. *
  4. * 它是把两个Servlet的响应内容合并输出。
  5. * 注意:
  6. * 这种包含是动态包含。
  7. *
  8. * 动态包含的特点:
  9. * 各编译各的,只是最后合并输出。
  10. */
  11. public class RequestDemo8 extends HttpServlet {
  12. public void doGet(HttpServletRequest request, HttpServletResponse response)
  13. throws ServletException, IOException {
  14. response.getWriter().write("I am request demo8 ");
  15. //1.拿到请求调度对象
  16. RequestDispatcher rd = request.getRequestDispatcher("/RequestDemo9");
  17. //2.实现包含的操作
  18. rd.include(request, response);
  19. }
  20. public void doPost(HttpServletRequest request, HttpServletResponse response)
  21. throws ServletException, IOException {
  22. doGet(request, response);
  23. }
  24. }
  25. /**
  26. * 被包含者
  27. */
  28. public class RequestDemo9 extends HttpServlet {
  29. public void doGet(HttpServletRequest request, HttpServletResponse response)
  30. throws ServletException, IOException {
  31. response.getWriter().write("include request demo 9 ");
  32. }
  33. public void doPost(HttpServletRequest request, HttpServletResponse response)
  34. throws ServletException, IOException {
  35. doGet(request, response);
  36. }
  37. }

练习

使用servlet+html实现学生管理系统,实现添加,列表功能。暂时还没有用到数据库,可以把学生信息保存到一个txt文件中。
参考思路:由HTML中编写表单,Servlet中定义接收请求的方法,最终把表单数据输出到控制台即可。Servlet的配置方式选择基于web.xml的方式。