JavaWeb——【Request】——一篇文章学会Request

Request


1.概述

在Servlet API 中,定义了一个 HttpServlet Request 接口,它继承自 ServletRequest 专门用来封装 HTTP 请求消息。由于 HTTP 请求消息分为请求行、请求消息头和请求消息体三部分,因此,在 HttpServlet Request 接口中定义了获取请求行、请求头和请求消息体的相关方法

2.获取请求信息方法

当访问 Servler 时,会在请求消息的请求行中,包含请求方法、请求资源名,请求路径等信息,为了获取这些信息,在 HttpServler Request 接口中,定义了一系列用于获取请求行信息的方法

方法声明 功能描述
String getMethod() 获取 http 请求消息中请求方式(GET、POST)
String getRequestURI() 获取 URL 的主机和端口之后、参数部分之前的部分
String getQueryString() GET 提交 url 地址后的参数字符串
String getServletPath() 获取 Servlet 的名称或 Servlet 所映射的路径
String getRemoteAddr() 获取访问者 ip 地址

/**

*获取请求行的内容

*@author weidong */

public class LineServlet extends HttpServlet {

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

//1、获得请求方式



//2、获得请求的资源相关的内容

String requestURI = request.getRequestURI(); StringBuffer requestURL = request.getRequestURL();




System.out.println("uri:" + requestURI);

System.out.println("url:" + requestURL);

//获得web应用的名称



//地址后的参数的字符串



//3、获得客户机的信息---获得访问者IP地址

String remoteAddr = request.getRemoteAddr(); System.out.println("IP:" + remoteAddr);

}

}

3.获取请求消息头的方法

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

方法声明 功能描述
String getHeader(String name) 获取 http 请求头的指定字段
Enumeration getHeaders(String name) 获取指定头的多个值
Enumeration getHeaderNames() 获取一个包含所有请求头字段的Enumeration 对象
String getContentLength() 该方法用于获取 Content_Length 头字段的值,结果为 int 类型
int getContentType() 获取 ContentType 头字段的值,结果为 String类型
String getCharacterEncoding() 获取消息实体部分字符编码
/**

*获取头的方法

*@author weidong */

public class HeaderServlet extends HttpServlet {

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

PrintWriter writer = response.getWriter();






//1、获得指定的头



//2、获得所有的头的名称

Enumeration<String> headerNames = request.getHeaderNames(); writer.print(header);

while (headerNames.hasMoreElements()) {

String headerName = headerNames.nextElement(); String headerValue = request.getHeader(headerName); System.out.println(headerName + ":" + headerValue); writer.print(headerName + " : " + headerValue +"<br>");
}

}

}

4.获取请求参数

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

方法 功能
String getParameter(String name) 获取指定名称的参数
String[] getParameterValues(String name); 如果有多个参数同名,可以使用此方法获取
Enumeration getParameterNames() 获取所有参数对象
Map<String,String[]> getParameterMap(); 以键值对的形式获取参数

public class LoginServlet extends HttpServlet {

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

String username = request.getParameter("username"); System.out.println("用户名" + username);


String password = request.getParameter("password"); System.out.println("密码" + password);

System.out.println("------------------");

//获取参数名为" hobby"的值

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






for (int i = 0; i < hobbys.length; i++) { System.out.println("爱好:" + hobbys[i]);

}

System.out.println("------------------");


Enumeration<String> parameterNames = request.getParameterNames(); while (parameterNames.hasMoreElements()) {

System.out.println(parameterNames.nextElement());

}

System.out.println("------------------");

// 获得所有的参数 参数封装到一个 Map<String,String[]>

Map<String, String[]> parameterMap = request.getParameterMap(); for (Map.Entry<String, String[]> entry : parameterMap.entrySet())

{

System.out.println(entry.getKey());

for (String str : entry.getValue()) {

System.out.println(str);

}

System.out.println("---------------------------");

}

}

}

输出
在这里插入图片描述

4.1.请求参数乱码(POST)

上面的代码,如果输入的是中文字符,那么会产生乱码问题,如下图
在这里插入图片描述
是因为浏览器在传递请求参数时,默认采用 UTF-8 的编码,但是在解码时采用的是默认的ISO8859-1,因此导致控制台打印参数信息出现乱码

解决

在Http ServletRequest 接口中,提供了一个 sctCharacterEncoding()方法,该方法用于设置 request 对象的解码方式
在这里插入图片描述
此时取到的值为:
在这里插入图片描述

4.2.请求参数乱码(GET)

使用 sctCharacterEncoding()方法解决乱码问题只针对 POST 请求,而对 GET 请求是无效的,为了解决 GET 方式提交表单的中文乱码问题,可以先使用错误码表 ISO8859-1 将用户名重新编码,然后使用码表 UTF-8 进行解码。

//get 方式乱码解决
String username = request.getParameter("username");//乱码
//先用 iso8859-1 编码 在使用 utf-8 解码
username = new String(username.getBytes("iso8859-1"),"UTF-8");

5.Request 域存取和请求转发

5.1. Request 域对象

Reruest 对象不仅可以获取一系列数据,还可以通过属性传递数据,在 ServletRequest 接口中,定义了一系列操作属性的方法:
setAttribute(key, value)

向 request 域中存入一个值(键值对形式)
getAttribute(key)

获取 request 域中指定键的值
removeAttribute()

删除 request 域中指定键的值
getAttributeNames()

获取域中所有
注意:存储在 request 域中的对象数据只有当前请求有效,而对其它请求无效。

5.2.请求转发

在ServletI 中,如果当前 Web 资源不想处理它的访问请求,可以通过 forward()方法将当前请求传递给其他的 Web 资源进行处理,这种方式称为请求转发。

forward()方法工作原理

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

相关方法介绍

request.getRequestDispatcher(path);

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

RequestDispatcher 接口方法介绍

forward(ServletRequest request, ServletResponse response)

  • 1.该方法用于将请求从一个 Servlet 传递给另外的一个 Web
  • 2.注意:该方法必须在响应提交给客户端之前被调用,否则将抛出

IllegalStateException 异常

include(ServletRequest request,ServletResponse response)

1.该方法用于将其它资源当做响应内容包含进来

Servlet1

public class Servlet1 extends HttpServlet {

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

//想 request 域中存储数据

request.setAttribute("name", "LiSi");





//servlet1 将请求转发给 servlet2 RequestDispatcher dispatcher =

request.getRequestDispatcher("/servlet2");

//执行转发的方法

dispatcher.forward(request, response);

}

}

Servlet2

public class Servlet2 extends HttpServlet {

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

//从 request 域中取出数据

Object attribute = request.getAttribute("name"); response.getWriter().write("hello: " + attribute);

}

}

6.注册

注意:为了方便演示,这里需要将 login.html 页面转成 jsp 界面,关于 jsp 之后会有很详细的介绍,现在无需深究(和 html 没有太大的区别)
login.jsp

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

<!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=ISO-8859-1"> <title>登陆</title>

</head>
<body>

<div align="center">

<!-- jsp 代码取值,现阶段无需理解 -->

<div><%=request.getAttribute("msg")==null?"":request.getAttribute("m

sg")%></div>


<form action="http://localhost:8080/LoginDemo_Request/login" method="post">

用户名:<input type="text" name="username" /><br /> 密码:

<input type="text" name="password" /><br />

<input type="submit" value="登陆" /> </form>

</div>

</body>

</html>

需要添加的功能

1.注册功能,添加新的界面进行注册,完成注册后将数据保存到数据库中

添加注册 Servlet,设置请求参数编码为 UTF-8,解决参数提交乱码,获取提交过来的用户名和密码
public class RegisterServlet extends HttpServlet {

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

request.setCharacterEncoding("UTF-8");

//获取所有参数

Map<String, String[]> maps = request.getParameterMap(); for (Entry<String,String[]> set : maps.entrySet()) {

System.out.println(set.getKey());

System.out.println(Arrays.toString(set.getValue()));

}

}

}

添加注册 jsp 界面


<div align="center">

<form

action="http://localhost:8080/LoginDemo_Request/registerServlet" method="post">

用户名:<input type="text" name="username" /><br /> 密码: <input type="text" name="password" /><br /> <input type="submit" value="注册" />
</form>

</div>

编写注册方法,在 UserDao 里面编写添加插入用户信息到数据库的方法,方法参数接受一个用户对象,返回 int 类型的值,调用者通过获取该值来判断是否插入成功

//添加用户的方法

public int addUser(User user) throws SQLException{

//操作数据库

QueryRunner runner = new QueryRunner(C3P0Utils.getDataSource());

String sql = "insert into user values(?,?,?)";

runner.update(sql,user.getId(),user.getUsername(),user.getPassword()

);

}

测试方法

另外,一般开发中,用户 id 是唯一的,这里使用了 UUID 工具类来帮我们生成一个唯一ID,关于 UUID 介绍,请看 UUID 文档

@Test

public void t2(){

UserDao userDao = new UserDao();

User user = new User();

user.setId(UUID.randomUUID().toString());

user.setUsername("bbb");

user.setPassword("123456");

try {

userDao.addUser(user);

} catch (SQLException e) {

e.printStackTrace();

}

}

编写 Service 层,在 UserService 中添加注册方法,并调用 UserDao 的 addUser 方法进行完成注册逻辑。


/**

*注册

*@param user 用户信息对象

*@return

*@throws SQLException */

public int register(User user) throws SQLException{ UserDao dao=new UserDao();

return dao.addUser(user);

}

编写 RegisterServlet,获取到用户信息后,需要将用户信息进行封装,封装到 User 对象中,使用 BeanUtils 组件,帮助我们封装对象的属性(id 需要自己设置),之后调用 UserService 中的 register 方法,传入封装好的 User 对象,进行注册,代码如下:

public class RegisterServlet extends HttpServlet {

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

request.setCharacterEncoding("UTF-8");

//获取所有参数

Map<String, String[]> maps = request.getParameterMap(); for (Entry<String, String[]> set : maps.entrySet()) {

System.out.println(set.getKey());

System.out.println(Arrays.toString(set.getValue()));

}

User user = new User();

try {

BeanUtils.populate(user, maps);

} catch (IllegalAccessException e) { e.printStackTrace();

} catch (InvocationTargetException e) { e.printStackTrace();

}

//手动添加 UUID

user.setId(UUID.randomUUID().toString());

UserService service = new UserService();

try {

service.register(user);

} catch (SQLException e) { e.printStackTrace();

}

//默认注册成功,跳转登陆界面

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

}

}


7.登陆案例

修改之前的登陆逻辑:

如果登陆成功,请求转发到 index.jsp 界面,并显示登陆的账号名字

如果登陆失败,请求转发回到登陆界面,并给出相应的提示。

注意:

这里登陆成功后,往 request 域中存入了用户名,在 index.jsp 界面使用 jsp 来获取域中的值,现阶段只需要了解(之后会学到),只需理解 request 与可以存入值即可。

登陆失败后,向域里面存入消息,登陆的 jsp 进行取值显示

<%=request.getAttribute("msg")==null?"":request.getAttribut


e("msg")%>


//判断 user 是否为空 if (user == null) {

//若为空 写"用户名和密码不匹配"

//response.getWriter().print("用户名和密码不匹配,5 秒后自动跳转登陆界面

");

//response.setHeader("refresh", "5;url=/LoginDemo/login.html"); request.getRequestDispatcher("/login.jsp").forward(request,

response);

} else {

//在登录成功的代码中获得原来的次数并且+1,存回到 SErvletContext 域中。

//登录成功的时候 获得原来的次数 + 1

Integer count = (Integer)

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

// 存回到 ServletContext 域中

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

//向 request 域中存入用户名

request.setAttribute("username", user.getUsername());

//若不为空 写"xxx:欢迎回来"

//response.getWriter().print(user.getUsername() + ":欢迎回来");

//使用转发,转发到主界面

request.getRequestDispatcher("/index.jsp").forward(request,

response);

}

8.转发和重定向区别

  • 使用重定后,之前的 request 中存放的变量全部失效,并进入一个新的 request 作用域。
  • 试音转发后,之前的 request 中存放的变量不会失效,就像把两个页面拼到了一起。
  • 重定向两次请求,转发一次请求
  • 重定向地址栏的地址变化,转发地址不变
  • 重新定向可以访问外部网站,转发只能访问内部资源
  • 转发的性能要优于重定向

怎么选择是重定向还是转发呢?通常情况下转发更快,而且能保持 request 内的对象,所以他是第一选择。但是由于在转发之后,浏览器中 URL 仍然指向开始页面,此时如果重载当前页面,开始页面将会被重新调用。如果你不想看到这样的情况,则选择转发。

9.ServletContext 域与 Request 域的生命周期

ServletContext

  • 创建:服务器启动
  • 销毁:服务器关闭
  • 域的作用范围:整个 web 应用

request

  • 创建:访问时创建 request
  • 销毁:响应结束 request 销毁
  • 域的作用范围:一次请求中
发布了230 篇原创文章 · 获赞 250 · 访问量 28万+

猜你喜欢

转载自blog.csdn.net/weixin_42247720/article/details/103888667