前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Web-第九天 ServletContext&Response&request学习

Web-第九天 ServletContext&Response&request学习

作者头像
Java帮帮
发布2018-07-27 14:52:15
5070
发布2018-07-27 14:52:15
举报

Web-第九天 ServletContext&Response&request学习

ServletContext & Response

今日内容介绍

  • 案例一:记录网站的登录成功的人数
  • 案例二:文件下载
  • 案例三:点击切换验证码

今日内容学习目标

  • 掌握ServletContext对象的使用
  • 使用response成功发送中文数据
  • 使用response可以设置响应头

第1章 案例:记录网站的登录成功的人数.

1.1 案例需求:

登录成功后,5秒后跳转到某个页面,在页面中显示您是第x位登录成功的用户.

1.2 相关知识点:

1.2.1 ServletContext

服务器启动的时候,为每个WEB应用创建一个单独的ServletContext对象,我们可以使用这个对象存取数据,用这个对象存取的数据可以在整个WEB应用中获得。可以使用如下方法存取数据

方法名

描述

setAttribute(String name,Object object)

向ServletContext中存数据

getAttribute(String name)

从ServletContext中取数据

removeAttribute(name)

从ServletContext中移除数据

1.3 案例分析:

1.4 代码实现:

/**

* 登录代码的Servlet

*/

public class UserCountServlet extends HttpServlet {

private static final long serialVersionUID = 1L;

@Override

public void init() throws ServletException {

// 初始化一个变量count的值为0.

int count = 0;

// 将这个值存入到ServletContext中.

this.getServletContext().setAttribute("count", count);

}

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

try {

response.setContentType("text/html;charset=UTF-8");

// 1.接收表单提交的参数.

String username = request.getParameter("username");

String password = request.getParameter("password");

// 2.封装到实体对象中.

User user = new User();

user.setUsername(username);

user.setPassword(password);

// 3.调用业务层处理数据.

UserService userService = new UserService();

User existUser = userService.login(user);

// 4.根据处理结果显示信息(页面跳转).

if(existUser == null){

// 登录失败

response.getWriter().println("<h1>登录失败:用户名或密码错误!</h1>");

}else{

// 登录成功

// 记录次数:

int count = (int) this.getServletContext().getAttribute("count");

count++;

this.getServletContext().setAttribute("count", count);

response.getWriter().println("<h1>登录成功:您好:"+existUser.getNickname()+"</h1>");

response.getWriter().println("<h3>页面将在5秒后跳转!</h3>");

response.setHeader("Refresh", "5;url=/day09/CountServlet");

}

} catch (Exception e) {

e.printStackTrace();

}

}

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

doGet(request, response);

}

}

public class CountServlet extends HttpServlet {

private static final long serialVersionUID = 1L;

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

// 获得Count的值。

response.setContentType("text/html;charset=UTF-8");

int count = (int) this.getServletContext().getAttribute("count");

response.getWriter().println("<h1>您是第"+count+"位登录成功的用户!</h1>");

}

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

doGet(request, response);

}

}

1.5 总结:

1.5.1 ServletContext:读取WEB工程下的文件

ServletContext对象,tomcat为每一个web项目单独创建的一个上下文(知上知下贯穿全文)对象。就有功能:

1.可以在多个servlet之间共享数据

存放:setAttribute()

获得:getAttribute()

删除:removeAttribute()

2.可以获得当前WEB项目中的指定资源(文件)

3.可以进行整个web项目初始化数据设置

在web.xml可以给整个web项目配置初始化参数

<!-- 全局初始化参数(整个项目) -->

<context-param>

<param-name>参数名</param-name>

<param-value>参数值</param-value>

</context-param>

动物世界

主演:李易峰 / 迈克尔·道格拉斯 / 周冬雨

猫眼电影演出 广告

购买

在实际开发中,有时候可能会需要读取Web应用中的一些资源文件,比如配置文件,图片等。为此,在ServletContext接口中定义了一些读取Web资源的方法,这些方法是依靠Servlet容器来实现的。Servlet容器根据资源文件名相对于Web应用的路径,返回关联资源文件的IO流、资源文件在文件系统的绝对路径等。

方法说明

功能描述

Set getResourcePaths(String path)

返回一个Set集合,集合中包含资源目录中子目录和文件的路径名称。参数path必须以正斜线(/)开始,指定匹配资源的部分路径

String getRealPath(String path)

返回资源文件在服务器文件系统上的真实路径(文件的绝对路径)。参数path代表资源文件的虚拟路径,它应该以正斜线开始(/)开始,“/”表示当前Web应用的根目录,如果Servlet容器不能将虚拟路径转换为文件系统的真实路径,则返回null

URL getResource(String path)

返回映射到某个资源文件的URL对象。参数path必须以正斜线(/)开始,“/”表示当前Web应用的根目录

InputStream getResourceAsStream(String path)

返回映射到某个资源文件的InputStream输入流对象。参数path传递规则和getResource()方法完全一致

了解了ServletContext接口中用于获得Web资源路径的方法后,接下来通过一个案例,分步骤演示如何使用ServletContext对象读取资源文件

1.5.2 代码实现

  • 加载配置文件

package cn.com.javahelp.servlet;

import java.io.*;

import java.util.Properties;

import javax.servlet.*;

import javax.servlet.http.*;

public class ReadFileServlet extends HttpServlet {

public void doGet(HttpServletRequest request,

HttpServletResponse response)throws ServletException, IOException {

ServletContext context = this.getServletContext();

PrintWriter out = response.getWriter();

//获取相对路径中的输入流对象

InputStream in = context.getResourceAsStream("/WEB-INF/classes/javahelp.properties");

Properties pros = new Properties();

pros.load(in);

out.println("Company=" + pros.getProperty("Company") + "<br>");

out.println("Address=" + pros.getProperty("Address") + "<br>");

}

public void doPost(HttpServletRequest request,

HttpServletResponse response)throws ServletException, IOException {

this.doGet(request, response);

}

}

  • 开发者需要获取的是资源的绝对路径。接下来,通过使用getRealPath(String path)方法获取资源文件的绝对路径。

package cn.com.javahelp.servlet;

import java.io.*;

import java.util.Properties;

import javax.servlet.*;

import javax.servlet.http.*;

public class ReadFileServlet extends HttpServlet {

public void doGet(HttpServletRequest request,

HttpServletResponse response)throws ServletException, IOException {

PrintWriter out = response.getWriter();

ServletContext context = this.getServletContext();

//获取文件绝对路径

String path = context

.getRealPath("/WEB-INF/classes/javahelp.properties");

FileInputStream in = new FileInputStream(path);

Properties pros = new Properties();

pros.load(in);

out.println("Company=" + pros.getProperty("Company") + "<br>");

out.println("Address=" + pros.getProperty("Address") + "<br>");

}

public void doPost(HttpServletRequest request,

HttpServletResponse response)throws ServletException, IOException {

this.doGet(request, response);

}

}

1.5.3 初始化参数

  • servlet的初始化参数

通过ServletConfig对象获得

  • 整个项目的初始化参数

通过ServletContext对象获得

1.5.4 扩展:类加载器读取文件

public static void readFile() throws IOException{

// 使用类的加载器来读取文件.

// 类的加载器用来加载class文件,将class文件加载到内存.

InputStream is = ReadFileUtils.class.getClassLoader().getResourceAsStream("db.properties");

Properties properties = new Properties();

properties.load(is);

String driverClass = properties.getProperty("driverClass");

String url = properties.getProperty("url");

String username = properties.getProperty("username");

String password = properties.getProperty("password");

System.out.println(driverClass);

System.out.println(url);

System.out.println(username);

System.out.println(password);

}

第2章 案例:完成文件的下载.

2.1 需求:

在登录成功后,页面跳转到文件下载的列表的页面,点击列表中的某些链接,下载文件.

2.2 相关知识点:

2.2.1 HttpServletResponse对象

在Servlet API中,定义了一个HttpServletResponse接口,它继承自ServletResponse接口,专门用来封装HTTP响应消息。由于HTTP响应消息分为状态行、响应消息头、消息体三部分,因此,在HttpServletResponse接口中定义了向客户端发送响应状态码、响应消息头、响应消息体的方法,接下来,本节将针对这些方法进行详细的讲解。

2.2.1.1 发送状态码相关的方法

当Servlet向客户端回送响应消息时,需要在响应消息中设置状态码。为此,在HttpServletResponse接口中,定义了两个发送状态码的方法,具体如下。

1).setStatus(int status)方法

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

2).sendError(int sc)方法

该方法用于发送表示错误信息的状态码,例如,404状态码表示找不到客户端请求的资源。在response对象中,提供了两个重载的sendError(int sc)方法,具体如下:

public void sendError(int code) throws java.io.IOException

public void sendError(int code, String message) throws java.io.IOException

在上面重载的两个方法中,第一个方法只是发送错误信息的状态码,而第二个方法除了发送状态码外,还可以增加一条用于提示说明的文本信息,该文本信息将出现在发送给客户端的正文内容中。

2.2.1.2 发送响应消息头相关的方法

当Servlet向客户端发送响应消息时,由于HTTP协议的响应头字段有很多种,为此,在HttpServletResponse接口中,定义了一系列设置HTTP响应头字段的方法,如表4-1所示。

表4-1 设置响应消息头字段的方法

方法声明

功能描述

void addHeader(String name, String value)

这两个方法都是用来设置HTTP协议的响应头字段,其中,参数name用于指定响应头字段的名称,参数value用于指定响应头字段的值。不同的是,addHeader()方法可以增加同名的响应头字段,而setHeader()方法则会覆盖同名的头字段

void setHeader(String name, String value)

void addIntHeader(String name,int value)

这两个方法专门用于设置包含整数值的响应头。避免了使用addHeader()与setHeader()方法时,需要将int类型的设置值转换为String类型的麻烦

void setIntHeader(String name,int value)

void setContentLength(int len)

该方法用于设置响应消息的实体内容的大小,单位为字节。对于HTTP协议来说,这个方法就是设置Content-Length响应头字段的值

void setContentType(String type)

该方法用于设置Servlet输出内容的MIME类型,对于HTTP协议来说,就是设置Content-Type响应头字段的值。例如,如果发送到客户端的内容是jpeg格式的图像数据,就需要将响应头字段的类型设置为“image/jpeg”。需要注意的是,如果响应的内容为文本,setContentType()方法的还可以设置字符编码,如:text/html;charset=UTF-8

void setCharacterEncoding(String charset)

该方法用于设置输出内容使用的字符编码,对HTTP 协议来说,就是设置Content-Type头字段中的字符集编码部分。一般不使用。

需要注意的是,在表4-1列举的一系列方法中,addHeader()、setHeader()、addIntHeader()、setIntHeader()方法都是用于设置各种头字段的,而setContetType() 和setCharacterEncoding()方法用于设置字符编码,这些设置字符编码的方法可以有效解决乱码问题。

2.2.1.3 发送响应消息体相关的方法

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

1).getOutputStream()方法

该方法所获取的字节输出流对象为ServletOutputStream类型。由于ServletOutputStream是OutputStream的子类,它可以直接输出字节数组中的二进制数据。因此,要想输出二进制格式的响应正文,就需要使用getOutputStream()方法。

2).getWriter()方法

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

了解了response对象发送响应消息体的两个方法后,接下来,通过一个案例来学习这两个方法的使用。

在Eclipse中创建Web项目chapter04,在项目的src目录下,新建一个名称为cn.com.javahelp. chapter04.response的包,在包中编写一个名为PrintServlet的Servlet类,该类中使用了response对象的getOutPutStream()方法获取输出流对象,如文件4-1所示。

文件4-1 PrintServlet.java

package cn.com.javahelp.chapter04.response;

import java.io.*;

import javax.servlet.*;

import javax.servlet.http.*;

public class PrintServlet extends HttpServlet {

public void doGet(HttpServletRequest request,

HttpServletResponse response)throws ServletException, IOException {

String data = "javahelp";

// 获取字节输出流对象

OutputStream out = response.getOutputStream();

out.write(data.getBytes());// 输出信息

}

public void doPost(HttpServletRequest request,

HttpServletResponse response)throws ServletException, IOException {

doGet(request, response);

}

}

在web.xml中配置完PrintServlet的映射后,启动Tomcat服务器,在浏览器的地址栏中输入地址“http://localhost:8080/chapter04/PrintServlet”访问PrintServlet,浏览器的显示结果如图4-2所示。

图 4-2

从图4-2中可以看出,浏览器显示出了response对象响应的数据。由此可见,response对象的getOutputStream()方法可以很方便的发送响应消息体。

接下来,对文件4-1进行修改,使用getWriter()方法发送消息体,修改后的代码如文件4-2所示。

文件4-2 PrintServlet.java

package cn.com.javahelp.chapter04.response;

import java.io.*;

import javax.servlet.*;

import javax.servlet.http.*;

public class PrintServlet extends HttpServlet {

public void doGet(HttpServletRequest request,

HttpServletResponse response)throws ServletException, IOException {

String data = "javahelp";

// 获取字符输出流对象

PrintWriter print = response.getWriter();

print.write(data); // 输出信息

}

public void doPost(HttpServletRequest request,

HttpServletResponse response)throws ServletException, IOException {

doGet(request, response);

}

}

重启Tomcat服务器,在浏览器的地址栏中输入地址 “http://localhost:8080/chapter04/PrintServlet”再次访问PrintServlet,浏览器的显示结果同样如图4-2所示。

注意:

虽然response对象的getOutputStream()和getWriter()方法都可以发送响应消息体,但是,它们之间互相排斥,不可同时使用,否则会发生IllegalStateException异常,如图4-3所示。

图4-3

图4-3中发生异常的原因就是在Servlet中,调用response.getWriter() 方法之前已经调用了response.getOutputStream() 方法。

2.2.2 文件下载原理

对于文件下载,相信读者并不会陌生,因为通常在上网时所下的图片、文档和影片等都是文件下载的范畴。现在很多网站都提供了下载各类资源的功能,因此在学习Web开发过程中,有必要学习文件下载的实现方式。

实现文件下载功能比较简单,通常情况下,不需要使用第三方组件实现,而是直接使用Servlet类和输入/输出流实现。与访问服务器文件不同的是,要实现文件的下载,不仅需要指定文件的路径,还需要在HTTP协议中设置两个响应消息头,具体如下:

//设定接收程序处理数据的方式

Content-Disposition: attachment; filename =

//设定实体内容的MIME类型

Content-Type:application/x-msdownload

浏览器通常会直接处理响应的实体内容,需要在HTTP响应消息中设置两个响应消息头字段,用来指定接收程序处理数据内容的方式为下载方式。当单击“下载”超链接时,系统将请求提交到对应的Servlet。在该Servlet中,首先获取下载文件的地址,并根据该地址创建文件字节输入流,然后通过该流读取下载文件内容,最后将读取的内容通过输出流写到目标文件中。

2.3 代码实现

public class DownloadServlet extends HttpServlet {

private static final long serialVersionUID = 1L;

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

// 1.接收参数

String filename = request.getParameter("filename");

// 2.完成文件下载:

// 2.1设置Content-Type头

String type = this.getServletContext().getMimeType(filename);

response.setHeader("Content-Type", type);

// 2.2设置Content-Disposition头

response.setHeader("Content-Disposition", "attachment;filename="+filename);

// 2.3设置文件的InputStream.

String realPath = this.getServletContext().getRealPath("/download/"+filename);

InputStream is = new FileInputStream(realPath);

// 获得response的输出流:

OutputStream os = response.getOutputStream();

int len = 0;

byte[] b = new byte[1024];

while((len = is.read(b))!= -1){

os.write(b, 0, len);

}

is.close();

}

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

doGet(request, response);

}

}

2.4 总结:

2.4.1 中文文件的下载:

  • Firefox浏览器下载中文文件的时候采用的是Base64的编码.
  • IE浏览器,谷歌浏览器等,下载中文文件的时候采用的URL的编码.
  • 可以使用工具类“DownloadUtils.java”进行处理

/**

* 文件下载的Servlet

*/

public class DownloadServlet extends HttpServlet {

private static final long serialVersionUID = 1L;

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

// 1.接收参数

String filename = new String(request.getParameter("filename"));

System.out.println(filename);

// 2.完成文件下载:

// 2.1设置Content-Type头

String type = this.getServletContext().getMimeType(filename);

response.setHeader("Content-Type", type);

// 2.3设置文件的InputStream.

String realPath = this.getServletContext().getRealPath("/download/"+filename);

// 根据浏览器的类型处理中文文件的乱码问题:

String agent = request.getHeader("User-Agent");

System.out.println(agent);

if(agent.contains("Firefox")){

filename = base64EncodeFileName(filename);

}else{

filename = URLEncoder.encode(filename,"UTF-8");

}

// 2.2设置Content-Disposition头

response.setHeader("Content-Disposition", "attachment;filename="+filename);

InputStream is = new FileInputStream(realPath);

// 获得response的输出流:

OutputStream os = response.getOutputStream();

int len = 0;

byte[] b = new byte[1024];

while((len = is.read(b))!= -1){

os.write(b, 0, len);

}

is.close();

}

public static String base64EncodeFileName(String fileName) {

BASE64Encoder base64Encoder = new BASE64Encoder();

try {

return "=?UTF-8?B?"

+ new String(base64Encoder.encode(fileName

.getBytes("UTF-8"))) + "?=";

} catch (UnsupportedEncodingException e) {

e.printStackTrace();

throw new RuntimeException(e);

}

}

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

doGet(request, response);

}

}

2.4.2 response解决中文输出乱码问题

在开发中,如果需要响应给浏览器中文数据,我们需要使用getWriter()方法,tomcat使用getWriter()处理字符时,默认编码时ISO8859-1。响应给浏览器的数据,此时为乱码。在开发中我们需要使用setCharacterEncoding方法来设置编码。此时响应给浏览器的数据为正常数据,但浏览器查看编码,可能使我们查看到内容仍为乱码,需要使用响应头 content-type进行设置。

在HttpServletResponse对象中,提供了两种解决乱码的方案,具体如下:

  • 第一种方式:

// 设置HttpServletResponse使用utf-8编码,此数据提供给tomcat使用。

response.setCharacterEncoding("utf-8");

// 通知浏览器查看编码为utf-8

response.setHeader("Content-Type","text/html;charset=utf-8");

  • 第二种方式:

// 使用通用方法,setContentType底层自动调用了setCharacterEncoding

response.setContentType("text/html;charset=utf-8");

通常情况下,为了使代码更加简洁,会采用第二种方式。实现代码如下文所示:

package cn.com.javahelp.chapter04.response;

import java.io.*;

import javax.servlet.*;

import javax.servlet.http.*;

public class ChineseServlet extends HttpServlet {

public void doGet(HttpServletRequest request,

HttpServletResponse response) throws ServletException, IOException {

//设置字符编码

response.setContentType("text/html;charset=utf-8");

String data="中国";

PrintWriter out = response.getWriter();

out.println(data);

}

public void doPost(HttpServletRequest request,

HttpServletResponse response) throws ServletException, IOException {

doGet(request,response);

}

}

启动Tomcat服务器,在浏览器的地址栏中输入地址“http://localhost:8080/day14/ChineseServlet”访问ChineseServlet,浏览器显示出了正确的中文字符,如下图所示。

第3章 案例:点击切换验证码

3.1 需求:

在访问登录页面时,需要生产验证码。从而防止用户使用程序恶意登录。

3.2 分析

3.3 代码实现

  • 步骤1:修改login.jsp页面,确定验证码图片显示的位置
  • 步骤2:拷贝VerifyCodeServlet实现类

public class VerifyCodeServlet extends HttpServlet {

private static final long serialVersionUID = 1L;

//生成图片

protected void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

//1 高和宽

int height = 30;

int width = 60;

String data = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";

Random random = new Random();

//2 创建一个图片

BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

//3 获得画板

Graphics g = image.getGraphics();

//4 填充一个矩形

// * 设置颜色

g.setColor(Color.BLACK);

g.fillRect(0, 0, width, height);

g.setColor(Color.WHITE);

g.fillRect(1, 1, width-2, height-2);

// * 设置字体

g.setFont(new Font("宋体", Font.BOLD|Font.ITALIC, 25));

//5 写随机字

for(int i = 0 ; i < 4 ; i ++){

// 设置颜色--随机数

g.setColor(new Color(random.nextInt(255), random.nextInt(255), random.nextInt(255)));

// 获得随机字

int index = random.nextInt(data.length());

String str = data.substring(index, index + 1);

// 写入

g.drawString(str, width/6 * (i + 1), 20);

}

//6 干扰线

for(int i = 0 ; i < 3 ; i ++){

// 设置颜色--随机数

g.setColor(new Color(random.nextInt(255), random.nextInt(255), random.nextInt(255)));

// 随机绘制先

g.drawLine(random.nextInt(width), random.nextInt(height), random.nextInt(width),random.nextInt(height));

// 随机点

g.drawOval(random.nextInt(width), random.nextInt(height), 2, 2);

}

//end 将图片响应给浏览器

ImageIO.write(image, "jpg", response.getOutputStream());

}

protected void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

doGet(request, response);

}

}

  • 步骤3:编写web.xml文件

<servlet>

<servlet-name>VerifyCodeServlet</servlet-name>

<servlet-class>cn.com.javahelp.web.servlet.VerifyCodeServlet</servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>VerifyCodeServlet</servlet-name>

<url-pattern>/VerifyCodeServlet</url-pattern>

</servlet-mapping>

3.4 点击切换

  • 添加点击图片或文字,更换验证码
  • 代码实现,点击图片或文件,都可以更换验证码图片。

<div>

<img id="imgId" onclick="changeImg()" style="cursor: pointer;"

src="${pageContext.request.contextPath}/VerifyCodeServlet"/>

<a href="javascript:void(0)" onclick="changeImg()" >换一张</a>

<script type="text/javascript">

function changeImg(){

$("#imgId").attr("src","${pageContext.request.contextPath}/VerifyCodeServlet?t="+new Date());

}

</script>

</div>

request

今日内容介绍

  • 案例一:完成用户注册的案例
  • 案例二:完善用户登录,显示错误信息

今日内容学习目标

  • 使用request获得表单请求参数
  • 使用request完成请求转发,并成功在一次请求中传递数据

第4章 案例:完成用户注册的功能:

4.1 需求:

网站首页上点击注册的链接,跳转到注册页面,在注册页面中输入信息.完成注册:(将数据保存到数据库中).

4.2 相关知识点:

4.2.1 HttpServletRequest对象

在Servlet API中,定义了一个HttpServletRequest接口,它继承自ServletRequest接口,专门用来封装HTTP请求消息。由于HTTP请求消息分为请求行、请求消息头和请求消息体三部分,因此,在HttpServletRequest接口中定义了获取请求行、请求头和请求消息体的相关方法,接下来,本节将针对这些方法进行详细地讲解。

4.2.1.1 获取请求行信息的相关方法

当访问Servlet时,会在请求消息的请求行中,包含请求方法、请求资源名、请求路径等信息,为了获取这些信息,在HttpServletRequest接口中,定义了一系列用于获取请求行的方法,如表4-2所示。

表4-2 获取请求行的相关方法

方法声明

功能描述

String getMethod()

该方法用于获取HTTP请求消息中的请求方式(如GET、POST等)

String getRequestURI()

该方法用于获取请求行中资源名称部分,即位于URL的主机和端口之后、参数部分之前的部分

String getQueryString()

该方法用于获取请求行中的参数部分,也就是资源路径后面问号(?)以后的所有内容

String getProtocol()

该方法用于获取请求行中的协议名和版本,例如,HTTP/1.0或HTTP/1.1

String getContextPath()

该方法用于获取请求URL中属于WEB应用程序的路径,这个路径以“/”开头,表示相对于整个WEB站点的根目录,路径结尾不含“/”。如果请求URL属于WEB站点的根目录,那么返回结果为空字符串("")

String getServletPath()

该方法用于获取Servlet的名称或Servlet所映射的路径

String getRemoteAddr()

该方法用于获取请求客户端的IP地址,其格式类似于“192.168.0.3”

String getRemoteHost()

该方法用于获取请求客户端的完整主机名,其格式类似于“pc1.javahelp.com.cn”。需要注意的是,如果无法解析出客户机的完整主机名,该方法将会返回客户端的IP地址

int getRemotePort()

该方法用于获取请求客户端网络连接的端口号

String getLocalAddr()

该方法用于获取Web服务器上接收当前请求网络连接的IP地址

String getLocalName()

该方法用于获取Web服务器上接收当前网络连接IP所对应的主机名

int getLocalPort()

该方法用于获取Web服务器上接收当前网络连接的端口号

String getServerName()

该方法用于获取当前请求所指向的主机名,即HTTP请求消息中Host头字段所对应的主机名部分

int getServerPort()

该方法用于获取当前请求所连接的服务器端口号,即如果HTTP请求消息中Host头字段所对应的端口号部分

String getScheme()

该方法用于获取请求的协议名,例如http、https或ftp

StringBuffer getRequestURL()

该方法用于获取客户端发出请求时的完整URL,包括协议、服务器名、端口号、资源路径等信息,但不包括后面的查询参数部分。注意,getRequestURL()方法返回的结果是StringBuffer类型,而不是String类型,这样更便于对结果进行修改

在表4-2中,列出了一系列用于获取请求消息行信息的方法,为了使读者更好地理解这些方法,接下来,通过一个案例来演示这些方法的使用。

在chapter04项目的src目录下,新建一个名称为cn.com.javahelp.request的包,在包中编写一个名为RequestLineServlet的类,该类中编写了用于获取请求行中相关信息的方法,如文件4-3所示。

文件4-3 RequestLineServlet.java

package cn.com.javahelp.request;

import java.io.*;

import javax.servlet.*;

import javax.servlet.http.*;

public class RequestLineServlet extends HttpServlet {

public void doGet(HttpServletRequest request,

HttpServletResponse response)throws ServletException, IOException {

response.setContentType("text/html;charset=utf-8");

PrintWriter out = response.getWriter();

// 获取请求行的相关信息

out.println("getMethod : " + request.getMethod() + "<br>");

out.println("getRequestURI : " + request.getRequestURI() + "<br>");

out.println("getQueryString:"+request.getQueryString() + "<br>");

out.println("getProtocol : " + request.getProtocol() + "<br>");

out.println("getContextPath:"+request.getContextPath() + "<br>");

out.println("getPathInfo : " + request.getPathInfo() + "<br>");

out.println("getPathTranslated : "

+ request.getPathTranslated() + "<br>");

out.println("getServletPath:"+request.getServletPath() + "<br>");

out.println("getRemoteAddr : " + request.getRemoteAddr() + "<br>");

out.println("getRemoteHost : " + request.getRemoteHost() + "<br>");

out.println("getRemotePort : " + request.getRemotePort() + "<br>");

out.println("getLocalAddr : " + request.getLocalAddr() + "<br>");

out.println("getLocalName : " + request.getLocalName() + "<br>");

out.println("getLocalPort : " + request.getLocalPort() + "<br>");

out.println("getServerName : " + request.getServerName() + "<br>");

out.println("getServerPort : " + request.getServerPort() + "<br>");

out.println("getScheme : " + request.getScheme() + "<br>");

out.println("getRequestURL : " + request.getRequestURL() + "<br>");

}

public void doPost(HttpServletRequest request,

HttpServletResponse response)throws ServletException, IOException {

doGet(request, response);

}

}

在web.xml中配置完RequestLineServlet的映射后,启动Tomcat服务器,在浏览器的地址栏中输入地址“http://localhost:8080/ day15/RequestLineServlet”访问RequestLineServlet,浏览器的显示结果如图4-14所示。

图4-14

从图4-14中可以看出,浏览器显示出了请求RequestLineServlet时,发送的请求行信息。由此可见,通过HttpServletRequest对象可以很方便的获取到请求行的相关信息。

4.2.1.2 获取请求消息头的相关方法

当请求Servlet时,需要通过请求头向服务器传递附加信息,例如,客户端可以接收的数据类型,压缩方式,语言等等。为此,在HttpServletRequest接口中,定义了一系列用于获取HTTP请求头字段的方法,如表4-3所示。

表4-3 获取请求消息头的方法

方法声明

功能描述

String getHeader(String name)

该方法用于获取一个指定头字段的值,如果请求消息中没有包含指定的头字段,getHeader()方法返回null;如果请求消息中包含有多个指定名称的头字段,getHeader()方法返回其中第一个头字段的值

Enumeration getHeaders(String name)

该方法返回一个Enumeration集合对象,该集合对象由请求消息中出现的某个指定名称的所有头字段值组成。在多数情况下,一个头字段名在请求消息中只出现一次,但有时候可能会出现多次

Enumeration getHeaderNames()

该方法用于获取一个包含所有请求头字段的Enumeration对象

int getIntHeader(String name)

该方法用于获取指定名称的头字段,并且将其值转为int类型。需要注意的是,如果指定名称的头字段不存在,返回值为-1;如果获取到的头字段的值不能转为int类型,将发生NumberFormatException异常

Long getDateHeader(String name)

该方法用于获取指定头字段的值,并将其按GMT时间格式转换成一个代表日期/时间的长整数,这个长整数是自1970年1月1日0点0分0秒算起的以毫秒为单位的时间值

在表4-3中,列出了一系列用于读取HTTP请求消息头字段的方法,为了更好地掌握这些方法,接下来通过一个案例来学习这些方法的使用。

在cn.com.javahelp.request包中编写一个名为RequestHeadersServlet的类,该类使用getHeaderNames()方法来获取请求消息头信息,如文件4-4所示。

文件4-4 RequestHeadersServlet.java

package cn.com.javahelp.request;

import java.io.IOException;

import java.io.PrintWriter;

import java.util.Enumeration;

import javax.servlet.*;

import javax.servlet.http.*;

public class RequestHeadersServlet extends HttpServlet {

public void doGet(HttpServletRequest request,

HttpServletResponse response)throws ServletException, IOException {

response.setContentType("text/html;charset=utf-8");

PrintWriter out = response.getWriter();

// 获取请求消息中所有头字段

Enumeration headerNames = request.getHeaderNames();

// 使用循环遍历所有请求头,并通过getHeader()方法获取一个指定名称的头字段

while (headerNames.hasMoreElements()) {

String headerName = (String) headerNames.nextElement();

out.print(headerName + " : "

+ request.getHeader(headerName)+ "<br>");

}

}

public void doPost(HttpServletRequest request,

HttpServletResponse response)throws ServletException, IOException {

doGet(request, response);

}

}

在web.xml中配置完RequestHeadersServlet映射后,启动Tomcat服务器,在浏览器的地址栏中输入地址“http://localhost:8080/day15/RequestHeadersServlet”访问RequestHeadersServlet,浏览器的显示结果如图4-15所示。

4.2.1.3 获取请求参数

在实际开发中,经常需要获取用户提交的表单数据,例如,用户名、密码、电子邮件等,为了方便获取表单中的请求参数,在HttpServletRequest接口中,定义了一系列获取请求参数的方法,如表4-4所示。

表4-4 获取请求参数的方法

方法声明

功能描述

String getParameter(String name)

该方法用于获取某个指定名称的参数值,如果请求消息中没有包含指定名称的参数,getParameter()方法返回null;如果指定名称的参数存在但没有设置值,则返回一个空串;如果请求消息中包含有多个该指定名称的参数,getParameter()方法返回第一个出现的参数值

String[] getParameterValues(String name)

HTTP请求消息中可以有多个相同名称的参数(通常由一个包含有多个同名的字段元素的FORM表单生成),如果要获得HTTP请求消息中的同一个参数名所对应的所有参数值,那么就应该使用getParameterValues()方法,该方法用于返回一个String类型的数组

Enumeration getParameterNames()

getParameterNames()方法用于返回一个包含请求消息中所有参数名的Enumeration对象,在此基础上,可以对请求消息中的所有参数进行遍历处理

Map getParameterMap()

getParameterMap()方法用于将请求消息中的所有参数名和值装入进一个Map对象中返回

表4-4中,列出了HttpServletRequest获取请求参数的一系列方法。其中,getParameter()方法用于获取某个指定的参数,而getParameterValues()方法用于获取多个同名的参数。接下来,通过一个具体的案例,分步骤讲解这两个方法的使用,具体如下:

(1)在day15项目的WebContent根目录下编写一个表单文件form.html,如文件4-5所示。

文件4-5 form.html

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"

"http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>Insert title here</title>

</head>

<body>

<form action="/day15/RequestParamsServlet" method="POST">

用户名:<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>

(2)在cn.com.javahelp.request包中编写一个名称为RequestParamsServlet的Servlet类,使用该Servlet获取请求参数,如文件4-6所示。

文件4-6 RequestParamsServlet.java

package cn.com.javahelp.request;

import java.io.*;

import javax.servlet.*;

import javax.servlet.http.*;

public class RequestParamsServlet extends HttpServlet {

public void doGet(HttpServletRequest request,

HttpServletResponse response)throws ServletException, IOException {

String name = request.getParameter("username");

String password = request.getParameter("password");

System.out.println("用户名:" + name);

System.out.println("密 码:" + password);

// 获取参数名为“hobby”的值

String[] hobbys = request.getParameterValues("hobby");

System.out.print("爱好:");

for (int i = 0; i < hobbys.length; i++) {

System.out.print(hobbys[i] + ", ");

}

}

public void doPost(HttpServletRequest request,

HttpServletResponse response)throws ServletException, IOException {

doGet(request, response);

}

}

在文件4-14中,由于参数名为“hobby”的值可能有多个,因此,需要使用getParameterValues()方法,获取多个同名参数的值,返回一个String类型的数组,通过遍历数组,打印出每个“hobby”参数对应的值。

(3)在web.xml中配置完RequestParamsServlet映射后,启动Tomcat服务器,在浏览器的地址栏中输入地址“http://localhost:8080/ day15/form.html”访问form.html页面,并填写表单相关信息,填写后的页面如图4-18所示。

图4-18 运行结果

(4)单击图4-18所示的“提交”按钮,在Eclipse的控制台打印出了每个参数的信息,如图4-19所示。

图4-19 运行结果

4.2.2 BeanUtils

BeanUtils 是 Apache commons组件的成员之一,主要用于简化JavaBean封装数据的操作。它可以给JavaBean封装一个字符串数据,也可以将一个表单提交的所有数据封装到JavaBean中。

使用第三方工具,需要导入jar包:

BeanUtils工具常用工具类有两个:BeanUtils、ConvertUtils。BeanUtils用于封装数据,ConvertUtils用于处理类型转换,常用API如下

方法

描述

BeanUtils对象

populate(Object bean, Map<String,String[]> properties)

将Map数据封装到指定Javabean中,一般用于将表单的所有数据封装到javabean

ConvertUtils

register(Converter converter, Class clazz)

注册类型转换器

  • 提供JavaBean User ,并提供对应的构造方法

public class User {

private String username;

private String password;

private int age;

private Date birthday;

public User() {

}

public User(String username, String password, int age, Date birthday) {

...

}

  • 功能1:封装表单数据,使用Map 模拟 request.getParameterMap()

@Test

public void demo01() throws Exception{

//将map数据封装给user

Map<String,String[]> properties = new HashMap<String,String[]>();

properties.put("username", new String[]{"jack"});

properties.put("password", new String[]{"1234"});

properties.put("age", new String[]{"18"});

User user = new User();

// 封装数据

BeanUtils.populate(user, properties);

System.out.println(user);

}

  • 功能2:封装表单数据,使用类型转换器

@Test

public void demo02() throws Exception{

//转换器

Map<String,String[]> properties = new HashMap<String,String[]>();

properties.put("username", new String[]{"jack"});

properties.put("password", new String[]{"1234"});

properties.put("age", new String[]{"18"});

properties.put("birthday", new String[]{"2012-12-21"});

User user = new User();

//1 创建BeanUtils提供时间转换器

DateConverter dateConverter = new DateConverter();

//2 设置需要转换的格式

dateConverter.setPattern("yyyy-MM-dd");

//3 注册转换器

ConvertUtils.register(dateConverter, java.util.Date.class);

//4 封装数据

BeanUtils.populate(user, properties);

System.out.println(user);

}

  • 功能3:编写工具类

public class MyBeanUtils {

/**

* 将数据封装给JavaBean,支持时间类型转换

* @param user

* @param properties

*/

public static void populate(Object user, Map<String,String[]> properties){

try {

//1 创建BeanUtils提供时间转换器

DateConverter dateConverter = new DateConverter();

//2 设置需要转换的格式

dateConverter.setPatterns(new String[]{"yyyy-MM-dd","yyyy-MM-dd HH:mm:ss"});

//3 注册转换器

ConvertUtils.register(dateConverter, java.util.Date.class);

//4 封装数据

BeanUtils.populate(user, properties);

} catch (Exception e) {

throw new RuntimeException(e);

}

}

}

使用

  • 工具类:高级(了解)

/**

* 高级封装,不需要new javabean

* @param beanClass

* @param properties

* @return

*/

public static <T> T populate(Class<T> beanClass, Map<String,String[]> properties){

try {

//1 使用反射创建实例

T bean = beanClass.newInstance();

//2.1 创建BeanUtils提供时间转换器

DateConverter dateConverter = new DateConverter();

//2.2 设置需要转换的格式

dateConverter.setPatterns(new String[]{"yyyy-MM-dd","yyyy-MM-dd HH:mm:ss"});

//2.3 注册转换器

ConvertUtils.register(dateConverter, java.util.Date.class);

//3 封装数据

BeanUtils.populate(bean, properties);

return bean;

} catch (Exception e) {

throw new RuntimeException(e);

}

}

使用

4.3 代码实现

package cn.com.javahelp.e_regist;

import java.io.IOException;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

/**

* 用户注册的Servlet

*/

public class RegistServlet extends HttpServlet {

private static final long serialVersionUID = 1L;

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

try{

request.setCharacterEncoding("UTF-8");

// 1.接收参数

String username = request.getParameter("username");

String password = request.getParameter("password");

String email = request.getParameter("email");

String name = request.getParameter("name");

String sex = request.getParameter("sex");

String telephone = request.getParameter("telephone");

// 2.封装数据

User user = new User();

user.setUsername(username);

user.setPassword(password);

user.setEmail(email);

user.setName(name);

user.setSex(sex);

user.setTelephone(telephone);

// 3.调用业务层处理数据

UserService userService = new UserService();

userService.regist(user);

// 4.页面跳转

response.sendRedirect(request.getContextPath()+"/login.htm");

}catch(Exception e){

e.printStackTrace();

}

}

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

doGet(request, response);

}

}

4.4 总结:

4.4.1 解决请求参数的中文乱码问题

在填写表单数据时,难免会输入中文,如姓名、公司名称等。在文件4-13中,由于HTML设置了浏览器在传递请求参数时,采用的编码方式是UTF-8,但在解码时采用的是默认的ISO8859-1,因此会导致乱码的出现。在浏览器的地址栏中输入地址“http://localhost:8080/day15/form.html”再次访问form.html页面,输入用户名为“悟空教程”以及相关表单信息,如图4-20所示。

图4-20 运行结果

单击图4-20中的“提交”按钮,这时,控制台打印出了每个参数的值,具体如图4-21所示。

图4-21 运行结果

从图4-21可以看出,当输入的用户名为中文时,出现了乱码问题。通过本任务的学习,读者将学会如何处理请求参数的中文乱码问题。

【实现步骤】

1.设置编码方式

在HttpServletRequest接口中,提供了一个setCharacterEncoding()方法,该方法用于设置request对象的解码方式,接下来,对文件4-6进行修改,修改后的代码如文件4-7所示。该方法用于返回请求消息的实体部分的字符集编码

文件4-7 RequestParamsServlet.java

package cn.com.javahelp.chapter04.request;

import java.io.*;

import javax.servlet.*;

import javax.servlet.http.*;

public class RequestParamsServlet extends HttpServlet {

public void doGet(HttpServletRequest request,

HttpServletResponse response)throws ServletException, IOException {

//设置request对象的解码方式

request.setCharacterEncoding("utf-8");

String name = request.getParameter("username");

String password = request.getParameter("password");

System.out.println("用户名:" + name);

System.out.println("密 码:" + password);

String[] hobbys = request.getParameterValues("hobby");

System.out.print("爱好:");

for (int i = 0; i < hobbys.length; i++) {

System.out.print(hobbys[i] + ", ");

}

}

public void doPost(HttpServletRequest request,

HttpServletResponse response)throws ServletException, IOException {

doGet(request, response);

}

}

2.查看运行结果

启动Tomcat服务器,再次访问form.html页面,输入中文用户名“悟空教程”以及相关表单信息,控制台打印的结果如图4-22所示。

图4-22 运行结果

从图4-22可以看出,控制台输出的参数信息没有出现乱码。需要注意的是,这种解决乱码的方式只对POST方式有效,而对GET方式无效。为了验证GET方式的演示效果,接下来,将form.html文件中method属性的值改为“GET”。重新访问form.html页面并填写中文信息,控制台的打印结果如图4-23所示。

图4-23 运行结果

从图4-23中可以看出,使用GET方式提交表单,用户名出现了乱码,这就验证了setCharacterEncoding()方法只对POST提交方式有效的结论。为了解决GET方式提交表单时出现的中文乱码问题,接下来,对文件4-7进行修改,增加一行代码,如下所示:

name=new String(name.getBytes("iso8859-1"),"utf-8");

重启Tomcat服务器,再次访问form.html网页,输入中文用户名“悟空教程”,这时,控制台的打印结果没有出现乱码,如图4-24所示。

图4-24

总结

第5章 案例:登录错误提示信息

5.1 需求

完善“登录”案例,如果用户填写信息有误,在当前表单页面中给出相应的提示。

5.2 相关知识点

5.2.1 通过Request对象传递数据

Request对象不仅可以获取一系列数据,还可以通过属性传递数据。在ServletRequest接口中,定义了一系列操作属性的方法,具体如下:

  • setAttribute()方法

该方法用于将一个对象与一个名称关联后存储进ServletRequest对象中,其完整语法定义如下:

public void setAttribute(java.lang.String name,java.lang.Object o);

需要注意的是,如果ServletRequest对象中已经存在指定名称的属性,setAttribute()方法将会先删除原来的属性,然后再添加新的属性。如果传递给setAttribute()方法的属性值对象为null,则删除指定名称的属性,这时的效果等同于removeAttribute()方法。

  • getAttribute()方法

该方法用于从ServletRequest对象中返回指定名称的属性对象,其完整的语法定义如下:

public java.lang.String getAttribute (java.lang.String name);

  • removeAttribute()方法

该方法用于从ServletRequest对象中删除指定名称的属性,其完整的语法定义如下:

public void removeAttribute(java.lang.String name);

  • getAttributeNames()方法

该方法用于返回一个包含ServletRequest对象中的所有属性名的Enumeration对象,在此基础上,可以对ServletRequest对象中的所有属性进行遍历处理。getAttributeNames()方法的完整语法定义如下:

public java.util.Enumeration getAttributeNames();

需要注意的是,只有属于同一个请求中的数据才可以通过ServletRequest对象传递数据。关于ServletRequest对象操作属性的具体用法,将在后面的小节进行详细讲解。在此,大家只需了解即可。

5.2.2 RequestDispatcher对象的应用

5.2.2.1 RequestDispatcher接口

当一个Web资源收到客户端的请求后,如果希望服务器通知另外一个资源去处理请求,这时,除了使用sendRedirect()方法实现请求重定向外,还可以通过RequestDispatcher接口的实例对象来实现。在ServletRequest接口中定义了一个获取RequestDispatcher对象的方法,如表4-5所示。

表4-5 获取RequestDispatcher对象的方法

方法声明

功能描述

getRequestDispatcher(String path)

返回封装了某个路径所指定资源的RequestDispatcher对象。其中,参数path必须以 “/”开头,用于表示当前Web应用的根目录。需要注意的是,WEB-INF目录中的内容对RequestDispatcher对象也是可见的,因此,传递给getRequestDispatcher(String path)方法的资源可以是WEB-INF目录中的文件

获取到RequestDispatcher对象后,最重要的工作就是通知其它Web资源处理当前的Servlet请求,为此,在RequestDispatcher接口中,定义了两个相关方法,如表4-6所示。

表4-6 RequestDispatcher接口的方法

方法声明

功能描述

forward(ServletRequest request,ServletResponse response)

该方法用于将请求从一个Servlet传递给另外的一个Web资源。在Servlet中,可以对请求做一个初步处理,然后通过调用这个方法,将请求传递给其它资源进行响应。需要注意的是,该方法必须在响应提交给客户端之前被调用,否则将抛出IllegalStateException异常

include(ServletRequest request,ServletResponse response)

该方法用于将其它的资源作为当前响应内容包含进来

表4-6列举的两个方法中,forward()方法可以实现请求转发,include()方法可以实现请求包含,关于请求转发相关知识,将在下面的小节中进行详细讲解。

请求包含:就是将当前页面和被包含页面的输出结果,合并一起响应给浏览器。

5.2.2.2 请求转发

在Servlet中,如果当前Web资源不想处理请求时,可以通过forward()方法将当前请求传递给其它的Web资源进行处理,这种方式称为请求转发。为了使读者更好地理解使用forward()方法实现请求转发的工作原理,接下来通过一张图来描述,如图4-25所示。

图4-25 forward()方法的工作原理

从图4-25中可以看出,当客户端访问Servlet1时,可以通过forward()方法将请求转发给其它Web资源,其它Web资源处理完请求后,直接将响应结果返回到客户端。

了解了forward()方法的工作原理后,接下来,通过一个案例来学习forward()方法的使用。

在day15项目的cn.com.javahelp.request包中编写一个名为RequestForwardServlet的Servlet类,该类使用forword()方法将请求转发到一个新的Servlet页面,如文件4-8所示。

文件4-8 RequestForwardServlet.java

package cn.com.javahelp.request;

import java.io.IOException;

import javax.servlet.*;

import javax.servlet.http.*;

public class RequestForwardServlet extends HttpServlet {

public void doGet(HttpServletRequest request,

HttpServletResponse response)throws ServletException, IOException {

response.setContentType("text/html;charset=utf-8");

// 将数据存储到request对象中

request.setAttribute("company", "上海满吉教育科技有限公司");

RequestDispatcher dispatcher = request.getRequestDispatcher("/ResultServlet");

dispatcher.forward(request, response);

}

public void doPost(HttpServletRequest request,

HttpServletResponse response)throws ServletException, IOException {

doGet(request, response);

}

}

通过使用forward()方法,将当前Servlet的请求转发到ResultServlet页面,在cn.com.javahelp.request包中编写一个名为ResultServlet的Servlet类,该类用于获取RequestForwardServlet类中保存在request对象中的数据并输出,ResultServlet类的代码实现。

ResultServlet.java

package cn.com.javahelp.request;

import java.io.*;

import javax.servlet.*;

import javax.servlet.http.*;

public class ResultServlet extends HttpServlet {

public void doGet(HttpServletRequest request,

HttpServletResponse response)throws ServletException, IOException {

response.setContentType("text/html;charset=utf-8");

// 获取PrintWriter对象用于输出信息

PrintWriter out = response.getWriter();

// 获取request请求对象中保存的数据

String company = (String) request.getAttribute("company");

if (company != null) {

out.println("公司名称:" + company + "<br>");

}

}

public void doPost(HttpServletRequest request,

HttpServletResponse response)throws ServletException, IOException {

doGet(request, response);

}

}

在web.xml中,添加完两个Servlet的映射信息后,启动Tomcat服务器,在浏览器中输入地址“http://localhost:8080/day15/RequestForwardServlet”访问RequestForwardServlet,浏览器的显示结果如图4-26所示。

图4-26 运行结果

5.3 分析

5.4 实现

  • 步骤1:修改“UserLoginServlet”,登录错误时,使用request设置设置错误信息,并请求转发到“login.jsp”.
    • 1.创建“login.jsp”
    • 2.添加页面编码(固定写法)

<%@ page language="java" contentType="text/html; charset=UTF-8"

pageEncoding="UTF-8"%>

  • 3.复制“login.html”内容到“login.jsp”

// * request作用设置错误信息

request.setAttribute("msg", "用户名或密码不匹配");

// * 请求转发到登录页面

request.getRequestDispatcher("login.jsp").forward(request, response);

  • 步骤2:在“login.jsp”页面显示错误信息(固定写法)

<%=request.getAttribute("msg") %>

5.5 总结

5.5.1 重定向和转发的区别:(redirect和forward的区别)

* 1.重定向的地址栏会发生变化,转发的地址栏不变.

* 2.重定向两次请求两次响应,转发一次请求一次响应.

* 3.重定向路径需要加工程名,转发的路径不需要加工程名.

* 4.重定向可以跳转到任意网站,转发只能在服务器内部进行转发.

第6章 总结

扩展知识

第7章 案例用户注册(使用beanutils)

7.1 创建数据库导入sql语句 引入jar包 工具类 数据库配置文件

7.2 创建servlet

import java.io.IOException;

import java.io.UnsupportedEncodingException;

import java.lang.reflect.InvocationTargetException;

import java.util.Map;

import java.util.UUID;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.beanutils.BeanUtils;

import cn.com.javahelp.domain.User;

import cn.com.javahelp.service.UserService;

public class RegisterServlet extends HttpServlet {

public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

request.setCharacterEncoding("UTF-8");

//1、获得请求数据

Map<String, String[]> map = request.getParameterMap();

//2、封装实体

User user = new User();

//使用BeanUtils进行映射封装(map中的key的名称与实体中的属性名称进行映射)

//bean代表要被封装实体 properties代表存储数据的map

try {

BeanUtils.populate(user, map);

} catch (IllegalAccessException | InvocationTargetException e) {

e.printStackTrace();

}

//手动封装uid

String uid = UUID.randomUUID().toString();

user.setUid(uid);

//3、传递数据到业务对象的方法

UserService service = new UserService();

//4、接受业务方法的处理结果

boolean isRegistSuccess = service.regist(user);

//5、为客户响应

if(isRegistSuccess){

//注册成功 返回登录页面

response.sendRedirect(request.getContextPath()+"/login.jsp");

}else{

response.setContentType("text/html;charset=UTF-8");

response.getWriter().write("对不起,注册失败,请联系管理员");

}

}

public void regist1(HttpServletRequest request, HttpServletResponse response) throws IOException{

request.setCharacterEncoding("UTF-8");

//1、获得请求数据

String username = request.getParameter("username");

String password = request.getParameter("password");

String email = request.getParameter("email");

String name = request.getParameter("name");

String sex = request.getParameter("sex");

String birthday = request.getParameter("birthday");

//2、封装实体

User user = new User();

//UUID:随机产生的永不不重复的字符串32位

String uid = UUID.randomUUID().toString();//36位 java产生uuid有四个-

user.setUid(uid);

user.setUsername(username);

user.setPassword(password);

user.setEmail(email);

user.setName(name);

user.setSex(sex);

user.setBirthday(birthday);

//3、传递数据到业务对象的方法

UserService service = new UserService();

//4、接受业务方法的处理结果

boolean isRegistSuccess = service.regist(user);

//5、为客户响应

if(isRegistSuccess){

//注册成功 返回登录页面

response.sendRedirect(request.getContextPath()+"/login.jsp");

}else{

response.setContentType("text/html;charset=UTF-8");

response.getWriter().write("对不起,注册失败,请联系管理员");

}

}

public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

doGet(request, response);

}

}

以下代码编写根据servlet需求不断的迭代

7.3 修改页面name属性 及action属性

7.4 创建实体类(根据表来写)

生成set&get方法,实际开发中一般都是set不会做无参,无参只是方便教学

public class User {

/*`uid` varchar(50) NOT NULL,

`username` varchar(20) DEFAULT NULL,

`password` varchar(50) DEFAULT NULL,

`name` varchar(20) DEFAULT NULL,

`email` varchar(30) DEFAULT NULL,

`telephone` varchar(20) DEFAULT NULL,

`birthday` date DEFAULT NULL,

`sex` varchar(10) DEFAULT NULL,

`state` int(11) DEFAULT NULL,

`code` varchar(64) DEFAULT NULL*/

private String uid;//唯一性标识 主键

private String username;//用户名

private String password;//密码

private String name;//真实姓名

private String email;//邮箱

private String telephone;

private String birthday;//生日

private String sex;//性别

private int state;

private String code;

public String getUid() {

return uid;

}

public void setUid(String uid) {

this.uid = uid;

}

public String getUsername() {

return username;

}

public void setUsername(String username) {

this.username = username;

}

public String getPassword() {

return password;

}

public void setPassword(String password) {

this.password = password;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public String getEmail() {

return email;

}

public void setEmail(String email) {

this.email = email;

}

public String getTelephone() {

return telephone;

}

public void setTelephone(String telephone) {

this.telephone = telephone;

}

public String getBirthday() {

return birthday;

}

public void setBirthday(String birthday) {

this.birthday = birthday;

}

public String getSex() {

return sex;

}

public void setSex(String sex) {

this.sex = sex;

}

public int getState() {

return state;

}

public void setState(int state) {

this.state = state;

}

public String getCode() {

return code;

}

public void setCode(String code) {

this.code = code;

}

}

7.5 request域对象的介绍

request对象同时也是一个域对象,开发人员通过request对象在实现转发时,把数据通过request对象带给其它web资源处理.当servlet1里面设置了值在servletN中也可以获取设置的值,作用范围:一次请求链中。

request

xxxAttribute();

生命周期:一次请求开始,到响应结束之前

setAttribute方法 设置

getAttribute方法 获取

removeAttribute方法 删除

getAttributeNames方法

request对象提供了一个getRequestDispatcher方法,该方法返回一个RequestDispatcher对象,调用这个对象的forward方法可以实现请求转发,从而共享请求中的数据

request.getRequestDispatcher("内部路径").forward(request,response)

7.5.1 请求转发(请求串,请求链)

请求转发可以实现路径的跳转操作.

实现:

New两个Servlet1 和Srevlet2

一个<a href="/day10/dis1?money=10">i_请求转发_借钱</a><br/> 前段链接加入money属性

Servlet1下request.getRequestDispatcher("内部路径").forward(request,response)路径为web.xml配置的跳转的Servlet的路径.System.out.println("我说:等会");response.getWriter().print("dis111111111111");request.setAttribute("name", "世纪"); request.getRequestDispatcher("/dis2").forward(request, response);

Servlet2下String money=request.getParameter("money");String name=(String) request.getAttribute("name");response.getWriter().print("dis2222222222222222");System.out.println("涛哥哥给你"+money+"块钱,然后我借给"+name);

7.5.2 请求转发和重定向的区别

1.请求转发是服务器内部跳转,地址栏不会发生改变

重定向地址栏会发生改变。

2.请求转发,只有一次请求,一次响应.

重定向,有两次请求,两次响应。

3.请求转发存在request域,可以共享数据.

重定向不存在request域。

4.请求转发只能在服务器的内部跳转,简单说,只能访问本站内资源。

重定向可以访问站外资源,也可以访问站内资源.

5.请求转发是由request 发起的 . request.getRequestDispatcher().forward()

重定向是由response 发起的 response.sendRedirect();

6.请求转发与重定向时路径写法不一样.

重定向要跳转的路径是浏览器在次发起的,是浏览器端路径:写法: /工程名/资源

请求转发是服务器内部跳转,这时它与浏览器无关 写法:/资源

7.5.3 请求包含

RequestDispatcher.include()方法用于将RequestDispatcher对象封装的资源内容作为当前响应内容的一部分包含进来,从而实现可编程的服务器端包含功能

被包含的Servlet程序不能改变响应消息的状态码和响应头,如果它里面存在这样的语句,这些语句的执行结果将被忽略.include在程序执行上效果类似forward,但是使用forward只有一个程序可以生成响应,include可以由多个程序一同生成响应 ----- 常用来页面布局

New两个html页面分别为 i1.html&i2.htmli1内容1111111111i2内容22222222222New一个Servlet get方法下request.getRequestDispatcher(“/i1.html”).include(request,response);request.getRequestDispatcher(“/i2.html”).include(request,response);最后在页面输出的内容为111111111122222222222是两个页面的所用内容. 包含原理

注意:转发与重定向不能一起使用

7.5.4 面试题:

注意:ServletContext域与Request域的生命周期比较?

ServletContext

创建:服务器启动就创建context对象

销毁:服务器关闭

作用范围:整个web应用

Request

创建:请求时创建

销毁:请求结束销毁

作用范围:一次请求链中

注意:转发与重定向的区别?
注意:客户端地址与服务器端地址的写法?

什么是客户端地址:客户端直接访问服务器的地址是客户端地址

通过客户端访问web应用 地址必须加上web应用的名称

什么是服务器端地址:web应用内部访问的地址服务器端地址

特点,访问时,不用写web应用名称

写地址时怎么区分是否加上web应用的名称

看在web应用内还是外

1)直接在地址栏中写url地址 --- 客户端地址

2)a标签的href --- 客户端地址

3)form表单的action-----客户端地址

4)location.href ---- 客户端地址

目前记住一个服务器端地址:转发 --- 服务器端地址

第8章 案例用户登录

8.1 修改页面action&name属性

8.2 创建servlet

import java.io.IOException;

import java.sql.SQLException;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import cn.com.javahelp.domain.User;

import cn.com.javahelp.service.UserService;

public class LoginServlet extends HttpServlet {

public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

request.setCharacterEncoding("UTF-8");

//1、接受数据

String username = request.getParameter("username");

String password = request.getParameter("password");

//2、封装实体

//3、传递数据

//4、接受结果

UserService service = new UserService();

User user = null;

try {

user = service.login(username,password);

} catch (SQLException e) {

e.printStackTrace();

}

//5、指派页面

if(user!=null){

//登录成功 跳转首页

response.sendRedirect(request.getContextPath()+"/index.jsp");

}else{

//登录失败

//返回登录页面 给予提示信息

request.setAttribute("loginInfo", "对不起 用户名或密码错误");

request.getRequestDispatcher("/login.jsp").forward(request, response);

}

}

public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

doGet(request, response);

}

}

8.3 修改jsp,设置动态提示信息(登录不成功)

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-06-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java帮帮 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ServletContext & Response
  • 第1章 案例:记录网站的登录成功的人数.
    • 1.1 案例需求:
      • 1.2 相关知识点:
        • 1.2.1 ServletContext
      • 1.3 案例分析:
        • 1.4 代码实现:
          • 1.5 总结:
            • 1.5.1 ServletContext:读取WEB工程下的文件
          • 动物世界
            • 1.5.2 代码实现
            • 1.5.3 初始化参数
            • 1.5.4 扩展:类加载器读取文件
        • 第2章 案例:完成文件的下载.
          • 2.1 需求:
            • 2.2 相关知识点:
              • 2.2.1 HttpServletResponse对象
              • 2.2.2 文件下载原理
            • 2.3 代码实现
              • 2.4 总结:
                • 2.4.1 中文文件的下载:
                • 2.4.2 response解决中文输出乱码问题
            • 第3章 案例:点击切换验证码
              • 3.1 需求:
                • 3.2 分析
                  • 3.3 代码实现
                    • 3.4 点击切换
                    • request
                    • 第4章 案例:完成用户注册的功能:
                      • 4.1 需求:
                        • 4.2 相关知识点:
                          • 4.2.1 HttpServletRequest对象
                          • 4.2.2 BeanUtils
                        • 4.3 代码实现
                          • 4.4 总结:
                            • 4.4.1 解决请求参数的中文乱码问题
                        • 第5章 案例:登录错误提示信息
                          • 5.1 需求
                            • 5.2 相关知识点
                              • 5.2.1 通过Request对象传递数据
                              • 5.2.2 RequestDispatcher对象的应用
                            • 5.3 分析
                              • 5.4 实现
                                • 5.5 总结
                                  • 5.5.1 重定向和转发的区别:(redirect和forward的区别)
                              • 第6章 总结
                              • 扩展知识
                              • 第7章 案例用户注册(使用beanutils)
                                • 7.1 创建数据库导入sql语句 引入jar包 工具类 数据库配置文件
                                  • 7.2 创建servlet
                                    • 7.3 修改页面name属性 及action属性
                                      • 7.4 创建实体类(根据表来写)
                                        • 7.5 request域对象的介绍
                                          • 7.5.1 请求转发(请求串,请求链)
                                          • 7.5.2 请求转发和重定向的区别
                                          • 7.5.3 请求包含
                                          • 7.5.4 面试题:
                                      • 第8章 案例用户登录
                                        • 8.1 修改页面action&name属性
                                          • 8.2 创建servlet
                                            • 8.3 修改jsp,设置动态提示信息(登录不成功)
                                            相关产品与服务
                                            验证码
                                            腾讯云新一代行为验证码(Captcha),基于十道安全栅栏, 为网页、App、小程序开发者打造立体、全面的人机验证。最大程度保护注册登录、活动秒杀、点赞发帖、数据保护等各大场景下业务安全的同时,提供更精细化的用户体验。
                                            领券
                                            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档