JavaWeb之HttpServletRequest与HttpServletResponse详解及快递管理系统实践
HttpServletRequest与HttpServletResponse详解及快递管理系统实践
第一章 HttpServletRequest请求对象
1. HttpServletRequest概述
- 概述:
HttpServletRequest extends ServletRequest
-> 请求对象(request对象) - 请求方式:
- GET请求:请求参数在浏览器地址栏上,没有请求体
- POST请求:请求参数在请求体中
- 请求参数形式:
key=value
形式,多个参数之间用&
链接 - 请求路径:
localhost:8080/web应用名称/资源?key=value&key=value
- key:页面上的name属性值
- value:页面上的value属性值
1.1 HttpServletRequest的组成
请求包含请求报文,请求报文由以下部分组成:
- 请求行:
- GET请求:
请求方式 请求路径?请求参数 协议版本
- POST请求:
请求方式 请求地址 协议版本
- GET请求:
- 请求头:对服务器解析请求的指导性信息
- 请求空行(可忽略)
- 请求体:
- GET请求没有请求体
- POST请求有请求体,包含请求参数
1.2 HttpServletRequest的作用
- 获取请求报文中的数据(主要是请求体内容)
- 实现请求转发(重定向)
- 作为域对象存储数据(请求域)
2. HttpServletRequest获取HTTP请求内容的方法
2.1 获取请求行方法
方法名 | 说明 |
---|---|
getMethod() | 获取请求方式(常用) |
getContextPath() | 获取当前应用上下文路径(在application context中设置的名字)(常用,四个方法中的重点) |
getRequestURI() | 获取请求地址,不带主机名 |
getRequestURL() | 获取请求地址,带主机名 |
@WebServlet("/request1")
public class Request1 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 获取请求方式String method = request.getMethod();System.out.println(method);System.out.println("======================");// 获取web应用名称String contextPath = request.getContextPath();System.out.println(contextPath);System.out.println("=======================");// 获取请求地址,不带主机名String requestURI = request.getRequestURI();System.out.println(requestURI);System.out.println("=======================");// 获取请求地址,带主机名StringBuffer requestURL = request.getRequestURL();System.out.println(requestURL);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doGet(request, response);}
}
测试页面:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>首页1</title>
</head>
<body>
<form action="/day05_request_response/request1" method="post">用户名:<input type="text" name="username"/><br/>密 码:<input type="password" name="password"/><br/><input type="submit" value="登录">
</form>
</body>
</html>
2.2 获取请求头信息方法
方法名 | 说明 |
---|---|
getHeader(String name) | 根据请求的key获取对应的value |
@WebServlet("/Servlet2")
public class Servlet2 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String host = req.getHeader("Host");System.out.println(host);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req,resp);}
}
常见请求头说明:
- Accept:浏览器能够处理的内容类型
- Accept-Charset:浏览器能够显示的字符集
- Accept-Encoding:浏览器能够处理的压缩编码
- Accept-Language:浏览器当前设置的语言
- Connection:浏览器与服务器之间连接的类型
- Cookie:当前页面设置的任何Cookie
- Host:发出请求的页面所在的域
- Referer:发出请求的页面的URL
- User-Agent:浏览器的用户代理字符串
2.3 获取请求体中的请求参数(重点)
-
请求参数位置:
- GET:请求参数在地址栏上 ->
localhost:8080/web应用名称/资源?key=value&key=value
- POST:请求参数在请求体中,格式为
key=value&key=value
- GET:请求参数在地址栏上 ->
-
参数说明:
- key:页面上的name属性值
- value:页面上的value属性值
- 实际需要获取的是value值,通过key获取
方法名 | 返回值类型 | 方法描述 |
---|---|---|
request.getParameter(“请求参数的name属性名”) | String | 根据提交参数的name获取对应的value |
request.getParameterValues(“请求参数的name属性名”) | String[] | 根据提交参数的name获取多个value |
request.getParameterMap() | Map<String,String[]> | 获取提交请求的所有参数,以键值对的方式存到map中 |
示例页面:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>获取提交参数</title>
</head>
<body><a href="/day05_request_response/request3?username=tom&password=111">访问request3</a><br/>
<hr color="red" size="2">
<form action="/day05_request_response/request3" method="get">用户名<input type="text" name="username"/><br/>密码<input type="text" name="password"/><br/>昵称<input type="text" name="nickname"/><br/>邮箱<input type="text" name="email"/><br/><!--复选框-->兴趣爱好<input type="checkbox" name="hobby" value="basketball"/>篮球<input type="checkbox" name="hobby" value="football"/>足球<input type="checkbox" name="hobby" value="yumaoball"/>羽毛球<input type="checkbox" name="hobby" value="pingpangball"/>乒乓球<br/><button type="submit">提交</button>
</form>
</body>
</html>
处理代码:
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import java.io.IOException;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;@WebServlet("/request3")
public class request3 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String username = req.getParameter("username");String password = req.getParameter("password");System.out.println("username:"+username+"password:"+password);System.out.println("=======================");String username1 = req.getParameter("username");String password1 = req.getParameter("password");String nickname = req.getParameter("nickname");String email = req.getParameter("email");System.out.println(username1+"..."+password1+"..."+nickname+"..."+email);System.out.println("==============");// 获取多个参数值String[] hobbies = req.getParameterValues("hobby");System.out.println("hobbies:"+ Arrays.toString(hobbies));System.out.println("===============");// 获取所有参数的Map集合Map<String, String[]> parameterMap = req.getParameterMap();Set<Map.Entry<String, String[]>> entries = parameterMap.entrySet();for (Map.Entry<String, String[]> entry : entries) {System.out.println(entry.getKey()+":"+Arrays.toString(entry.getValue()));}}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req,resp);}
}
2.4 解决获取请求参数乱码
2.4.1 乱码原因
- 编码和解码遵循的编码规则不一样
- 与tomcat的解码方式相关:
- tomcat10采用UTF-8编码
- tomcat获取请求参数主要是解析url中的参数
- tomcat8及以上版本优化:
- GET请求:参数在url上,直接用UTF-8解析
- POST请求:参数在请求体中,tomcat默认编码可能导致中文乱码
2.4.2 解决方法(主要针对post请求)
方法名 | 说明 |
---|---|
request.setCharacterEncoding(“UTF-8”) | 将获取到的请求参数设置为utf-8格式 |
@WebServlet("/request4")
public class Request4 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 处理请求中文乱码request.setCharacterEncoding("utf-8");String username = request.getParameter("username");String password = request.getParameter("password");System.out.println(username);System.out.println(password);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doGet(request, response);}
}
测试页面:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>首页request4</title>
</head>
<body>
<form action="/day05_request_response/request4" method="post">用户名:<input type="text" name="username"/><br/>密 码:<input type="password" name="password"/><br/><input type="submit" value="登录">
</form>
</body>
</html>
3. 请求转发
3.1 什么是请求转发
- 概述:通过项目下的一个资源将请求转发到另外一个该项目资源下的技术
- 特点:
- 整个过程只产生一个请求,浏览器地址栏不会变化
- 是服务器内部行为,浏览器不知情
- 在同一个请求中完成,只有一次请求
3.2 请求转发方法
方法名 | 说明 |
---|---|
RequestDispacher getRequestDispacher(String path) | 获取请求转发器对象 参数:path指目标资源路径 1. 转发到servlet:写servlet对应的url-pattern 2. 转发到页面:写页面路径 |
forward(request对象,response对象) | 实现请求转发,是RequestDispacher对象的方法 |
3.3 请求转发演示
// 浏览器访问request4,转发到request5或页面
@WebServlet("/request4")
public class request4 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 请求转发到request5// req.getRequestDispatcher("/request5").forward(req,resp);// 请求转发到WEB-INF下的index4.htmlreq.getRequestDispatcher("/WEB-INF/index.html").forward(req,resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);}
}
目标Servlet:
@WebServlet("/request5")
public class request5 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.getWriter().write("I am LiuDaDan");}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req,resp);}
}
3.4 总结
- 请求转发是服务器内部行为,浏览器只发一次请求
- 只能转发到当前web应用下的资源
- 地址栏不会变化
- 转发涉及的资源属于同一个请求
4. HttpServletRequest域对象
- 域对象对比:
- ServletContext:代表整个web应用程序,作用范围最大,全应用共享
- HttpServletRequest域(请求域):存储的数据只能在当前请求中共享,新请求无法获取
4.1 HttpServletRequest域对象方法
方法名 | 说明 |
---|---|
setAttribute(String key,Object o) | 存数据 |
getAttribute(String key) | 根据key获取value |
removeAttribute(String key) | 根据key删除value |
4.2 演示代码
@WebServlet("/request7")
public class request7 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {req.setAttribute("username","liudadan");// 必须请求转发,因为HttpServletRequest域只在同一请求中有效req.getRequestDispatcher("/request8").forward(req,resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req,resp);}
}
// 在request8中获取request7存储的数据
@WebServlet("/request8")
public class request8 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {Object username = req.getAttribute("username");System.out.println("username:"+username);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req,resp);}
}
第二章 HttpServletResponse响应对象
1. HttpServletResponse响应对象介绍
1.1 概念
HttpServletResponse extends ServletResponse
1.2 作用
给浏览器设置响应信息,包括:
- 响应行
- 响应头
- 响应体
2. HttpServletResponse使用
2.1 设置响应状态码(了解)
常见状态码:
- 200:响应成功
- 304:缓存
- 302:重定向
- 404:找不到资源
- 500:服务器内部错误
方法名 | 说明 |
---|---|
response.setStatus(状态码) | 设置响应行中的响应状态码 |
@WebServlet("/response1")
public class Response1 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// response.setStatus(404);System.out.println(1/0); // tomcat会默认给出报错信息}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doGet(request, response);}
}
响应状态码通常由tomcat自动设置,无需手动干预
2.2 设置响应头(了解)
响应头数据格式:k:v
方法名 | 说明 |
---|---|
setHeader(String key,String value) | 设置响应头的key和value |
@WebServlet("/response2")
public class Response2 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setHeader("myHeader","taoge"); // 设置响应头}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doGet(request, response);}
}
2.3 设置响应体(重要)
2.3.1 使用字符输出流响应
方法名 | 说明 |
---|---|
PrintWriter getWriter() | 使用字符流作出响应,需注意中文乱码 |
@WebServlet("/response3")
public class Response3 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.getWriter().write("<!DOCTYPE html>\n" +"<html lang=\"en\">\n" +"<head>\n" +" <meta charset=\"UTF-8\">\n" +" <title>Title</title>\n" +"</head>\n" +"<body>\n" +" hello,i am taoge,i am 16 years old\n" +"</body>\n" +"</html>");}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doGet(request, response);}
}
2.3.2 解决响应中文乱码
方法名 | 说明 |
---|---|
response.setContentType(“text/html;charset=utf-8”) | 设置响应头,解决中文乱码 |
@WebServlet("/response4")
public class Response4 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType("text/html;charset=utf-8");response.getWriter().write("你好,我是一个大帅哥!");}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doGet(request, response);}
}
2.4 设置浏览器重定向
概述:从web项目资源跳转到另一个资源,浏览器会发起两次请求,是一个新的请求。
方法名 | 说明 |
---|---|
response.sendRedirect(“重定向的资源路径”) | 请求重定向到另外一个资源中去 |
示例代码:
// 访问response5,重定向到response6
@WebServlet("/response5")
public class Response5 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 重定向到response6,需添加上下文地址response.sendRedirect(request.getContextPath()+"/response6");}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doGet(request, response);}
}@WebServlet("/response6")
public class Response6 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType("text/html;charset=utf-8");response.getWriter().write("你好,我是一个大帅哥!");}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doGet(request, response);}
}
2.5 重定向和请求转发区别
- 重定向会由浏览器发起新的请求,请求转发不会
- 重定向可以访问任意互联网资源,请求转发只能访问本项目资源
- 重定向不能访问本项目WEB-INF内的资源,请求转发可以
- 重定向涉及的资源不在同一次请求中,不能使用请求域;请求转发涉及的资源在同一次请求中,可以使用请求域
第三章 MVC模式
1. 为什么需要MVC
直接在Servlet中通过write
方法编写页面代码维护性差,需要将视图(页面)单独抽取为View层。但HTML无法展示动态数据,需要引入服务器端动态视图模板技术(如jsp或Thymeleaf)。
2. MVC概念
-
定义:web应用程序的开发模式
- M:Model模型 -> 处理数据
- V:View视图 -> 页面展示
- C:Controller控制器 -> 协调调度
-
理念:在表现层开发中,将封装数据的模型、显示界面的视图、协调调度的控制器分开。
-
好处:
- 实现组件解耦
- 便于单独维护
- 方便前后端工程师协作
3. MVC和三层架构之间关系
MVC属于表现层的设计模式,与三层架构(表现层、业务逻辑层、数据访问层)相辅相成,共同构成完整的应用程序架构。
第四章 快递管理系统第二期
1. 准备工作
1.1 数据库准备
导入资料中的deliver.sql
到数据库
1.2 项目搭建(delivery-system)
1.2.1 创建Javaweb工程(delivery-system)
1.2.2 导入页面
将资料中的页面导入到项目中
1.2.3 修改项目登录页面
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"version="6.0"><!-- 设置登录为欢迎页面 --><welcome-file-list><welcome-file>login.html</welcome-file></welcome-file-list>
</web-app>
改完web.xml后若仍跳转index.html,需清除浏览器缓存(ctrl+shift+delete)
1.2.4 导入数据库相关环境及创建类
导入数据库连接相关的工具类和配置文件
1.2.5 导入MD5加密工具类
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public final class MD5Utils {public static String encrypt(String strSrc) {try {char hexChars[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8','9', 'a', 'b', 'c', 'd', 'e', 'f' };byte[] bytes = strSrc.getBytes();MessageDigest md = MessageDigest.getInstance("MD5");md.update(bytes);bytes = md.digest();int j = bytes.length;char[] chars = new char[j * 2];int k = 0;for (int i = 0; i < bytes.length; i++) {byte b = bytes[i];chars[k++] = hexChars[b >>> 4 & 0xf];chars[k++] = hexChars[b & 0xf];}return new String(chars);} catch (NoSuchAlgorithmException e) {e.printStackTrace();throw new RuntimeException("MD5加密出错!!!");}}
}
1.2.6 导入pojo类
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;@AllArgsConstructor
@NoArgsConstructor
@Data
public class SysUser implements Serializable {private Integer id;private String username;private String password;private String nickname;
}
2. 登录业务代码
2.1 MVC架构模式实现
2.1.1 部署项目
按照标准流程部署web项目
2.1.2 修改login页面表单参数
调整表单的action和参数名,确保与后端接收一致
2.1.3 Controller层
import java.io.*;import com.atguigu.pojo.SysUser;
import com.atguigu.service.UserService;
import com.atguigu.service.impl.UserServiceImpl;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import jakarta.servlet.annotation.WebServlet;import java.io.IOException;
import java.sql.SQLException;@WebServlet("/user/login")
public class UserLoginController extends HttpServlet {private UserService userService = new UserServiceImpl();@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {try {// 设置请求参数编码格式request.setCharacterEncoding("UTF-8");response.setContentType("text/html;charset=UTF-8");// 获取请求参数String username = request.getParameter("username");String password = request.getParameter("password");// 调用service层方法SysUser sysUser = userService.login(username,password);if (sysUser!=null){request.getRequestDispatcher("/index.html").forward(request,response);}else{request.getRequestDispatcher("/login.html").forward(request,response);}} catch (SQLException e) {throw new RuntimeException(e);}}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doGet(request, response);}
}
2.1.4 Service层
接口:
public interface UserService {SysUser login(String username, String password) throws SQLException;
}
实现类:
public class UserServiceImpl implements UserService {private UserDao userDao = new UserDaoImpl();@Overridepublic SysUser login(String username, String password) throws SQLException {// 密码加密password = MD5Utils.encrypt(password);// 调用dao层SysUser sysUser = userDao.login(username,password);return sysUser;}
}
2.1.5 Dao层
接口:
public interface UserDao {SysUser login(String username, String password) throws SQLException;
}
实现类:
public class UserDaoImpl implements UserDao {private QueryRunner qr = new QueryRunner(DruidUtils.getDataSource());@Overridepublic SysUser login(String username, String password) throws SQLException {String sql = "select id,username,password,nickname from sys_user where username = ? and password = ?";SysUser sysUser = qr.query(sql, new BeanHandler<SysUser>(SysUser.class), username, password);return sysUser;}
}
2.2 解决转发页面样式丢失问题
修改login.html
和index.html
中的资源路径,添加web应用名称:
<head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>快递管理系统</title><meta name="Copyright" content="Douco Design." /><link href="/delivery/css/public.css" rel="stylesheet" type="text/css"><script type="text/javascript" src="/delivery/js/jquery.min.js"></script><script type="text/javascript" src="/delivery/js/global.js"></script>
</head>