乱码问题】BeanUtils使用软件开发三层架构项目结构"/>
WEB阶段2:http协议请求对象【转发重定向请求参数乱码问题】BeanUtils使用软件开发三层架构项目结构
http协议&请求对象【转发&重定向&请求参数乱码问题】&BeanUtils使用&软件开发三层架构项目结构
回顾
有时要清除浏览器的缓存,才能看到最新的结果,Chrome清除缓存的快捷键:ctrl+shift+del
-
软件架构分成哪两种,分别是什么含义
BS:浏览器服务器模式
CS: 客户端服务器模式
-
Tomcat目录结构
目录名 | 作用 |
---|---|
bin | 可执行文件,启动:startup.bat 关闭:shutdown.bat |
conf | 配置文件,核心配置文件:server.xml |
lib | 第三方的jar包 |
logs | 日志记录信息 |
temp | 临时目录 |
webapps | 项目发布目录 ROOT目录:启动tomcat以后默认的首页 在idea中开发的时候,没有这个首页 |
work | 工作目录,生成一些中间文件 |
-
tomcat部署的三种方式
直接复制到webapps
配置server.xml文件,添加Context path="/虚拟路径" docBase="真实地址" 不能有汉字,而且这个地址必须要存在
独立的xml文件 conf/catalina/localhost/文件名.xml 文件名就是访问地址 内容:Context docBase="真实地址"idea就是这种方式
-
Servlet与普通的Java程序的区别
- 实现什么接口:javax.servlet.Servlet接口,我们是继承于HttpServlet
- 运行在Tomcat的容器中
- service中的方法参数是:HttpServletRequest请求对象,HttpServletResponse响应对象
-
说出注解的作用
@WebServlet注解 | 作用 |
---|---|
name | servlet的名字,不能出现相同的名字 |
urlPatterns | 访问地址,可以指定多个 |
value | 同上 |
- Servlet的生命周期方法
方法 | 作用 | 运行次数 |
---|---|---|
void init(ServletConfig config) | 用户第一次访问的时候 | 执行1次 |
void service(ServletRequest req, ServletResponse res) | 每次请求都会执行 | 执行多次 |
void destroy() | 服务器关闭,销毁的时候 | 执行1次 |
学习目标
- HTTP请求协议的格式
- 能够理解HTTP协议请求内容
- 能够使用Request对象获取HTTP协议请求内容
- 请求对象的使用
- 能够处理HTTP请求参数的乱码问题
- 能够使用Request域对象
- 能够使用Request对象做请求转发
- 能够完成登录案例
学习内容
1. HTTP协议的概念
目标
- 什么是HTTP
- 它有什么特点
概念
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s3gnzGNV-1598790831863)(assets/1555154341398.png)]
HTTP: Hyper Text Transfer Protocol 超文本传输协议 (传输超文本的协议) (公交车),HTTP就是用来传输HTML的
HTML: Hyper Text Markup Language 超文本标记语言 (乘客)
默认端口号:80端口,不是8080,8080是Tomcat的。浏览器如果使用80端口,可以省略。
HTTP协议的特点:
- 格式比较简单,数据传输比较快
- 服务器如果接收到多次浏览器发送的请求,通过HTTP协议是不能判断这是一个用户的多次请求,还是多个用户的请求。因为HTTP协议是一个无状态的协议,不会记录用户的访问情况。
- 每次用户发送请求以后,得到了服务器的响应,连接就断开了。
- 在HTTP1.1的版本中,一次请求可以请求多个资源。1.0每次请求只会请求一个资源。
HTTPS
HTTPS:功能与HTTP是一样的,也是用来传输网页的
- 这是一个加密的传输协议
- 可以识别客户端与服务器端,防止假冒的第三方网站。
端口号是:443
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zvWzPgIe-1598790831882)(/assets/1552550764411.png)]
小结
- HTTP的作用是?用来传输HTML
- 默认的端口号是:80
- 特点:无状态的协议
2. HTTP请求的三个组成
目标
请求有哪三个组成部分
什么是请求
浏览器发送给服务器的数据
查看HTTP请求
-
在HTML页面上,制作2个表单提交页面,用户名和密码,get提交和post提交按钮,查看HTTP请求。
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>登录页面</title> </head> <body> <h2>GET请求</h2> <form action="demo1" method="get">用户名:<input type="text" name="username"><br>密码:<input type="password" name="password"><br><input type="submit" value="登录"> </form><h2>POST请求</h2> <form action="demo1" method="post">用户名:<input type="text" name="username"><br>密码:<input type="password" name="password"><br><input type="submit" value="登录"> </form> </body> </html>
-
查看浏览器与服务器的通讯,按F12打开窗口
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Du23bcQR-1598790831888)(assets/image-20200828091447858.png)]
请求的组成
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LmJyHmfn-1598790831896)(assets/image-20200828091752958.png)]
小结
请求由哪三个组成部分?
- 请求行:只有一行数据
- 请求头:由多个键值对组成,键和值之间是冒号
- 请求体:浏览器发送给服务器的数据
3. 请求信息的组成:请求行
目标
- 请求行的格式
- POST和GET请求的区别
请求行组成
POST /day27_01_request_war_exploded/demo1 HTTP/1.1
GET /day27_01_request_war_exploded/demo1?username=jack&password=123 HTTP/1.1
三个部分:
-
GET或POST,请求的方法
-
URI:Uniform Resource Identifer 统一资源标识符,用来标识服务器上唯一资源的名字
-
协议和版本
POST与GET的区别
POST方式 | GET方式 | |
---|---|---|
地址栏 | 没有参数 参数是在请求体中发送的 | GET后面有参数的值,地址与参数之间使用?分隔 如果有多个参数使用&分隔。数据是在请求行中发送的 |
大小 | 发送的数据没有大小限制 | 受浏览器的限制,最大是1K |
安全性 | 相对更加安全 | 参数是可以在地址栏上看到 |
缓存 | 不会使用缓存 | 浏览器会使用缓存 状态码: 200 表示从服务器上正确的获取数据 304 表示使用缓存 |
注:缓存只对静态资源起作用,动态资源是不起作用的。
浏览器上设置,让静态资源不使用缓存
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-txMD8wSQ-1598790831937)(assets/image-20200828094337482.png)]
小结
- 请求行由哪三个组成部分?
- 请求方式
- URI
- 协议和版本
- GET方法和POST方法传递数据有什么区别?
- 哪个使用缓存?GET
- 哪个在请求行中发送数据?GET
- POST在请求体中发送
- 哪个数据大小没有限制?POST
4. 请求信息的组成:请求头、请求体
目标
了解常见请求头的作用
常用请求头
格式:由键和值组成
请求头 | 描述 |
---|---|
referer | 获取从哪个页面跳转过来的 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GMcPn5qJ-1598790831939)(assets/image-20200828095003973.png)] |
if-modified-since | 缓存的页面才会有,缓存的时间,相差8小时 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q3pbcsp4-1598790831940)(assets/image-20200828095106961.png)] |
user-agent | 获取客户端操作系统和浏览器的信息 |
connection | 显示传输层TCP协议的连接状态:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-844bjkXw-1598790831942)(assets/image-20200828095845105.png)] |
host | 访问主机的名字和端口号:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CFQDpuu1-1598790831943)(assets/image-20200828095907489.png)] |
Accept-Language | [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ijjty6Wh-1598790831946)(assets/image-20200828100016558.png)] 接受的语言:中文-中国 |
请求体
- GET方法没有请求体
- POST方法才能请求体,请求体中是浏览器发送给服务器的数据
小结
完整的HTTP请求由以下内容组成:
5. 请求的方法:与请求行有关的方法
目标
与请求行相关的方法
什么是HttpServletRequest对象
请求对象,可以在doGet或doPost方法中直接使用这个对象。
HttpServletRequest是一个接口,它的实现类是由Tomcat实现的,对象由Tomcat创建。
请求对象:org.apache.catalina.connector.RequestFacade@26559f7c查看Tomcat的源码:
public class RequestFacade implements HttpServletRequest
如何修改Servlet的模板
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rtBtKta9-1598790831949)(assets/image-20200828100740947.png)]
如果没有重写doGet或doPost方法就会出现405的错误
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E8ggIX9b-1598790831950)(assets/image-20200828100958493.png)]
案例
需求
创建一个Servlet,用于获取请求行中相关信息的方法,并且输出到网页上。
效果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gQaWDYdF-1598790831951)(assets/image-20200828101707764.png)]
代码
package com.itheima.servlet;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;/*** 与请求行有关的方法* POST /day27_01_request_war_exploded/demo1 HTTP/1.1* GET /day27_01_request_war_exploded/demo1?username=jack&password=123 HTTP/1.1*/
@WebServlet("/demo1")
public class Demo1RequestLineServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType("text/html;charset=utf-8");PrintWriter out = response.getWriter();out.print("获取请求的方式:" + request.getMethod() + "<br/>");//URI: Uniform Resource Identifer 统一资源标识符,用来标识服务器上唯一资源的名字out.print("获取请求的URI:" + request.getRequestURI() + "<br/>");//URL: Uniform Resource Locator 统一资源定位符,这是一个可以直接访问的资源out.print("获取请求的URL:" + request.getRequestURL() + "<br/>");out.print("获取协议和版本:" + request.getProtocol() + "<br/>");out.print("获取?后面的参数,称为查询字符串:" + request.getQueryString() + "<br/>");}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doPost(request, response);}
}
小结
HttpServletRequest对象的方法 | 功能描述 |
---|---|
String getMethod() | 获取请求的方式,GET或POST |
String getRequestURI() | 获取URI (标识符) |
StringBuffer getRequestURL() | 获取URL (定位符) 比较长 |
String getProtocol() | 获取协议和版本 |
String getQueryString() | 获取?后面的参数 |
6. 请求的方法:与请求头有关的方法
目标
request对象中与请求头相关的方法
方法示例
需求
- 得到某个请求头的值
- 得到所有的请求头信息,并输出所有的请求值信息
效果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dMuAQHBr-1598790831953)(assets/image-20200828102515943.png)]
代码
package com.itheima.servlet;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;/*** 与请求头有关的方法*/
@WebServlet("/demo2")
public class Demo2HeaderServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType("text/html;charset=utf-8");PrintWriter out = response.getWriter();//通过请求头的键,获取请求头的值String host = request.getHeader("host");out.print("主机名和端口号:" + host + "<hr/>");//获取上一个页面的地址String referer = request.getHeader("referer");out.print("上一个页面的地址:" + referer + "<hr/>");//获取所有请求头的键(名字)Enumeration<String> headerNames = request.getHeaderNames();//遍历这个枚举类型while(headerNames.hasMoreElements()) {String name = headerNames.nextElement(); //表示其中的一个名字String value = request.getHeader(name); //通过名字获取值out.print("请求头名字:" + name + ",值:" + value + "<hr/>");}}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doPost(request, response);}
}
小结
请求方法 | 功能描述 |
---|---|
String getHeader(String headName) | 通过请求头的名字获取请求头的值 |
Enumeration<String> getHeaderNames() | 获取所有的请求头中名字(键) |
7. 请求头应用案例:判断浏览器的类型
目标
判断客户端是什么类型的浏览器:Edg、OPR、Chrome、Safari、Firefox、IE浏览器或其它
效果
分析
- 得到user-agent请求头,请求头的名字不区分大小写。
- 判断它的值是否包含指定了字符串,如果包含则表示是指定的浏览器。
- 否则就输出其它的浏览器
代码
package com.itheima.servlet;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;/*** 判断浏览器的类型*/
@WebServlet("/demo3")
public class Demo3BrowserServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType("text/html;charset=utf-8");PrintWriter out = response.getWriter();out.print("您的浏览器是:");//1.获取请求头:user-agentString agent = request.getHeader("user-agent");//2.判断它的值是否包含以下字符串:Edg、OPR、Chrome、Safari、Firefox、IE浏览器或其它//3.使用方法contains(),判断一个字符串是否包含另一个字符串//4.如果包含就输出相应的浏览器类型if (agent.contains("Edg")) {out.print("Microsoft Edge");}else if (agent.contains("OPR")) {out.print("Opera");}else if (agent.contains("Chrome")) {out.print("Google Chrome");}else if (agent.contains("Safari")) {out.print("Apple Safari");}else if (agent.contains("Firefox")) {out.print("Firefox");}else {out.print("IE浏览器或其它");}}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doPost(request, response);}
}
小结
案例的实现思路
- 获取user-agent请求头
- 判断它的值是否包含了指定的字符串
- 如果包含就输出浏览器的类型
8. 请求的方法:得到客户端提交的参数值【重点】
目标
使用request中的方法得到表单或地址栏上提交的参数值
获取参数的案例
需求
- 通过上面的方法得到注册页面的用户名和性别,输出到浏览器
- 得到所有的爱好,输出到浏览器
- 得到所有表单的名字和值,输出到浏览器
- 得到封装好的表单数据Map对象,输出到浏览器
效果
代码
HTML
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><title>这是登录页面</title>
</head>
<body>
<h2>用户注册</h2>
<form action="demo4" method="get">用户名: <input type="text" name="name"><br/>性别: <input type="radio" name="gender" value="男" checked="checked"/>男<input type="radio" name="gender" value="女"/>女 <br/>城市:<select name="city"><option value="广州">广州</option><option value="深圳">深圳</option><option value="珠海">珠海</option></select><br/>爱好:<input type="checkbox" name="hobby" value="上网"/>上网<input type="checkbox" name="hobby" value="上学"/>上学<input type="checkbox" name="hobby" value="上车"/>上车<input type="checkbox" name="hobby" value="上吊"/>上吊<br/><input type="submit" value="注册"/>
</form>
</body>
</html>
Servlet代码
package com.itheima.servlet;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Map;/*** 获取页面提交的参数*/
@WebServlet("/demo4")
public class Demo4RegisterServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType("text/html;charset=utf-8");PrintWriter out = response.getWriter();//得到注册页面的用户名和性别,输出到浏览器//1. 通过参数名获取参数值,方法的参数是:表单项的name或地址栏上提交的参数名String name = request.getParameter("name");String gender = request.getParameter("gender");out.print("名字:" + name + "<br/>");out.print("性别:" + gender + "<br/>");//2. 通过一个参数名,获取多个参数值,返回字符串数组//得到所有的爱好,输出到浏览器String[] hobbies = request.getParameterValues("hobby");out.print("爱好是:" + Arrays.toString(hobbies) + "<hr/>");//3. 得到所有表单的名字和值,输出到浏览器//获取所有表单项或参数的名字Enumeration<String> parameterNames = request.getParameterNames();//遍历每个元素while (parameterNames.hasMoreElements()) {String paramName = parameterNames.nextElement(); //获取其中一个参数名String value = request.getParameter(paramName); //获取一个参数值out.print("参数名:" + paramName + ",值:" + value + "<hr/>");}out.print("封装成Map:<br/>");//4.一次获取整个表单所有的参数名和值,并且封装成一个Map<String, String[]>对象,其中键是参数名,值是参数值Map<String, String[]> parameterMap = request.getParameterMap();parameterMap.forEach((paramName,value) -> {out.print("参数名:" + paramName + ",值:" + Arrays.toString(value) + "<hr/>");});}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doPost(request, response);}
}
小结
方法名 | 描述 |
---|---|
String getParameter(String name) | 通过参数名字,获取一个参数值 |
String[] getParameterValues(String name) | 通过参数名字,获取一组参数值,返回字符串数组。用于复选框 |
Enumeration<String> getParameterNames() | 获得所有的参数名 |
Map<String,String[]> getParameterMap() | 获取表单所有的参数名和值,封装成Map对象 其中键是参数名,值是参数值,是一个字符串的数组 |
扩展:设置默认打开的首页
每次开启项目,默认是打开index.jsp,index.html这个文件,我们可以设置自己的首页。
修改web.xml文件,设置欢迎页面
<!--设置欢迎页面列表-->
<welcome-file-list><welcome-file>login.html</welcome-file><welcome-file>register.html</welcome-file>
</welcome-file-list>
9. BeanUtils工具类的使用【重点】
目标
BeanUtils工具类中方法的使用
什么是BeanUtils
BeanUtils是Apache Commons组件的成员之一,主要用于简化JavaBean封装数据的操作。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mDzKF1Ob-1598790831958)(assets/1552556927816.png)]
BeanUtils是第三方组织写的工具类,要使用它,得先下载对应的工具jar包。
下载地址:/
相关的jar包
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qAonhvvx-1598790831960)(assets/1552557572028.png)]
BeanUtils常用方法
BeanUtils方法 | 说明 |
---|---|
public static void populate (Object target, Map source) | 作用:将map中的键和值复制到一个实体对象中 只会复制相同的属性,并且自动进行类型的转换。 参数1:目标对象,实体类 参数2:源对象,有数据的map |
案例:BeanUtils的使用
需求
- 得到表单所有的数据封装成Map
- 使用BeanUtils封装成一个User对象,并且输出到浏览器。
步骤
jar包必须放在web/WEB-INF/lib这个目录下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0twwVmJb-1598790831961)(assets/1552557742580.png)]
代码
JavaBean
package com.itheima.entity;import java.util.Arrays;/*** 属性名与表单的名字相同* Map中键的名字与表单的名字一样*/
public class User {private String name;private String gender;private String city;private String hobby[];@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", gender='" + gender + '\'' +", city='" + city + '\'' +", hobby=" + Arrays.toString(hobby) +'}';}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getGender() {return gender;}public void setGender(String gender) {this.gender = gender;}public String getCity() {return city;}public void setCity(String city) {this.city = city;}public String[] getHobby() {return hobby;}public void setHobby(String[] hobby) {this.hobby = hobby;}
}
页面地址
<form action="demo5" method="get">
Servlet
package com.itheima.servlet;import com.itheima.entity.User;
import org.apachemons.beanutils.BeanUtils;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;@WebServlet("/demo5")
public class Demo5BeanServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType("text/html;charset=utf-8");PrintWriter out = response.getWriter();//1. 得到表单所有的数据封装成MapMap<String, String[]> parameterMap = request.getParameterMap();//创建一个实体类对象User user = new User();//2. 使用BeanUtils封装成一个User对象,并且输出到浏览器。try {BeanUtils.populate(user,parameterMap);} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}out.print("封装后的对象:" + user);}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doPost(request, response);}
}
小结
BeanUtils常用方法 | 说明 |
---|---|
public static void populate(Object target, Map source) | 将一个Map封装成一个实体对象 |
补充:如何打开模块并执行
- 如图所示,选择从存在的源代码中导入模块
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r0EAQzu0-1598790831964)(assets/image-20191121143408593-1598588486139.png)]
- 找到需要导入的文件或目录
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0tQs96ZA-1598790831965)(assets/image-20191121143420608-1598588486139.png)]
- 刚导入的模块不能部署,点Run->Edit Configurations,点右边的Artifact,可能会找不到要部署的项目。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DSeMjBgH-1598790831968)(assets/image-20191121143434732-1598588486139.png)]
- 点File->Project Structure 选择Artifacts,点上面的加号。选择从模块中创建Web Application
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3cstpdmu-1598790831970)(assets/image-20191121143453713-1598588486139.png)]
- 选择新导入的模块
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ehgZlqUU-1598790831972)(assets/image-20191121143503069-1598588486140.png)]
- 再次进入部署页面,可以选择Artifact
10. 请求参数值汉字乱码的问题【重点】
目标
解决POST方法提交乱码的问题
请求参数值产生乱码的原因
Tomcat中请求默认的编码:iso-8859-1,这是欧洲码表,不支持汉字。我们需要将请求的编码改成utf-8,才会支持汉字。
POST方法乱码解决方法
-
方法:设置请求体的编码
request.setCharacterEncoding("utf-8")
-
上面这条语句一定要放在所有获取参数的方法前面
-
必须与HTML的编码相同
<meta charset="UTF-8">
Tomcat8.0中GET方法乱码的问题
以前Tomcat7 GET方法也是有乱码
8.0以后不用考虑汉字乱码的问题
小结
- POST乱码如何解决?setCharacterEncoding()
- GET乱码如何解决? 8.0以后没有乱码
11. 请求域有关的方法【重点】
目标
- 有哪三个作用域
- 操作作用域的方法
什么是作用域
Servlet中的3个作用域
请求域的范围
请求域 < 会话域 < 上下文域
作用域的操作方法
request与域有关的方法 | 作用 |
---|---|
Object getAttribute(“键”) | 通过键从请求域中获取值 |
void setAttribute(“键”,Object 值) | 向请求域中添加键和值,如果键存在就是修改 |
void removeAttribute(“键”) | 通过键删除键和值 |
案例:作用域的操作方法
需求
- Servlet创建一个键和值,在同一个Servlet中从请求域中取出信息,打印到浏览器上。
- 删除请求域中的键值对,再打印到浏览器上。
代码
package com.itheima.servlet;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;@WebServlet("/demo6")
public class Demo6AttributeServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType("text/html;charset=utf-8");PrintWriter out = response.getWriter();//向请求域中添加一个键和值request.setAttribute("user", "孙悟空");//从请求域中取出值String user = (String) request.getAttribute("user");//打印输出out.print("用户名:" + user + "<hr/>");//从请求域中删除键和值request.removeAttribute("user");//从请求域中取出值user = (String) request.getAttribute("user");//打印输出out.print("删除后用户名:" + user);}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doPost(request, response);}
}
小结
-
有哪三个作用域?
- 请求域:只在一次请求中起作用
- 会话域
- 上下文域
-
说说作用域方法的作用:
request域有关的方法 作用 Object getAttribute(“键”) 查询 void setAttribute(“键”,Object 数据) 添加或修改 void removeAttribute(“键”) 删除
12. 页面的跳转:转发
目标
- 转发的原理
- 转发的方法
疑问
-
能否在OneServlet中保存值到请求域中,在另一个TwoServlet中打印出来?
可以,但必须是同一次请求。使用转发可以在一次请求中访问多个Servlet,并且保证请求域中数据不丢失。
转发与重定向的作用
作用:就是进行页面的跳转
什么是转发
概念
案例
需求
实现从OneServlet中转发到TwoServlet
步骤
- OneServlet向请求域中添加了一个键和值,转发给TwoServlet
- TwoServlet就从请求域中取出键和值,打印到浏览器上。
效果
代码
OneServlet
package com.itheima.servlet;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;@WebServlet("/one")
public class Demo7OneServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType("text/html;charset=utf-8");PrintWriter out = response.getWriter();out.print("向请求域中添加了键和值");//向请求域中添加键和值request.setAttribute("user", "老王");/*转发的步骤:1. 获取转发器,提供参数:要转发的地址2. 通过转发器进行跳转: forward(请求,响应)*/request.getRequestDispatcher("two").forward(request, response);}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doPost(request, response);}
}
TwoServlet
package com.itheima.servlet;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;@WebServlet("/two")
public class Demo8TwoServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType("text/html;charset=utf-8");PrintWriter out = response.getWriter();out.print("<h2>这是Two</h2>");//从请求域中获取数据String user = (String) request.getAttribute("user");out.print("请求域中数据:" + user);}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doPost(request, response);}
}
小结转发的特点
-
地址栏:不会发生变化,显示的是上一个Servlet的地址
-
请求次数:只有一次请求
-
请求域中数据:不会丢失
-
转发使用哪个方法?
request.getRequestDispatcher("跳转的地址").forward(请求,响应)
13. 页面的跳转:重定向
目标
- 重定向原理
- 重定向的方法
什么是重定向
概念
重定向方法
响应对象方法
response.sendRedirect("要跳转的地址")
重定向案例
需求
从OneServlet重定向到TwoServlet
步骤
- 在OneServlet中向请求域中添加键和值
- 使用重定向到TwoServlet,在TwoServlet中看能否取出请求域的值
效果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Iu0JMrDU-1598790831973)(assets/image-20200828153536219.png)]
代码
OneServlet
package com.itheima.servlet;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;@WebServlet("/one")
public class Demo7OneServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType("text/html;charset=utf-8");PrintWriter out = response.getWriter();out.print("向请求域中添加了键和值");//向请求域中添加键和值request.setAttribute("user", "老王");/*转发的步骤:1. 获取转发器,提供参数:要转发的地址2. 通过转发器进行跳转: forward(请求,响应)request.getRequestDispatcher("two").forward(request, response);*///使用重定向进行页面跳转response.sendRedirect("two");}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doPost(request, response);}
}
TwoServlet
代码与前面相同,没有变化
重定向的特点
- 地址栏发生了变化,显示的是跳转后的地址
- 请求次数是两次
- 请求域中的数据丢失了
疑问
问:什么时候使用转发,什么时候使用重定向?
1. 如果要保留请求域中数据,使用转发,否则使用重定向。
2. 经验:查询使用转发,增删改使用重定向。
小结:重定向和转发的区别
区别 | 请求对象转发forward() | 响应对象重定向sendRedirect() |
---|---|---|
地址栏会不会发生变化 | 不会 | 会 |
由哪一方进行跳转 | 服务器端进行跳转 | 浏览器端进行跳转 |
请求域中数据会不会丢失 | 不会 | 会 |
14. 登录案例part1:项目搭建
目标
搭建项目的结构
需求
- 用户名和密码正确,将用户成功的信息保存在请求域中,转发到另一个页面,显示用户登录成功
- 用户名和密码错误,重定向到另一个html页面,显示登录失败。
- 使用表示层,业务层,数据访问层的三层结构实现
案例流程图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ogz8i5Ll-1598790831976)(assets/image-20200828155108370.png)]
实现步骤
创建用户表
CREATE DATABASE day27;
USE day27;create table `user`(id int primary key auto_increment,username varchar(20),password varchar(32));insert into `user`(username, password) values ('Jack','123'),('张三','456');select * from `user`;
登录页面
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><title>用户登录</title>
</head>
<body>
<h2>用户登录</h2>
<form action="login" method="post"><table><tr><td>用户名</td><td><input type="text" name="username"/></td></tr><tr><td>密码</td><td><input type="password" name="password"/></td></tr><tr><td colspan="2"><input type="submit" value="登录"/></td></tr></table>
</form>
</body>
</html>
创建WEB-INF\lib文件夹,导入jar包
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wnRF2JbS-1598790831978)(assets/image-20200828155625172.png)]
实体类User
package com.itheima.entity;public class User {private int id;private String username;private String password;@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + '\'' +", password='" + password + '\'' +'}';}public int getId() {return id;}public void setId(int id) {this.id = id;}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;}
}
sqlMapConfig.xml
模板
-
在new菜单下选择
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9Fhs2G6q-1598790831979)(assets/image-20200828160111042.png)]
-
创建一个模板
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3fL3yFnF-1598790831980)(assets/image-20200828160226477.png)]
文件放在src目录下
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis//DTD Config 3.0//EN"".dtd">
<configuration><settings><!--在控制台显示SQL语句--><setting name="logImpl" value="STDOUT_LOGGING"/></settings><!--定义实体类别名--><typeAliases><package name="com.itheima.entity"/></typeAliases><environments default="default"><!--环境变量--><environment id="default"><!--事务管理器--><transactionManager type="JDBC"/><!--数据源--><dataSource type="POOLED"><property name="driver" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/day27"/><property name="username" value="root"/><property name="password" value="root"/></dataSource></environment></environments><!--加载其它映射文件--><mappers><package name="com.itheima.dao"/></mappers>
</configuration>
会话工具类
通过工具类获取一个会话对象
定义成模板
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ufAiuvR5-1598790831982)(assets/image-20200828160802123.png)]
package com.itheima.utils;import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.IOException;
import java.io.InputStream;/*** 会话工具类*/
public class SqlSessionUtils {//会话工厂的创建类->会话工厂->会话private static SqlSessionFactory factory;static {//1.会话工厂的创建类SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();//2.得到配置文件的输入流try (InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml")) {//3.创建会话工厂factory = builder.build(inputStream);} catch (IOException e) {e.printStackTrace();}}/*** 得到会话对象* @return*/public static SqlSession getSession() {return factory.openSession();}}
15. 登录案例part2:数据访问层和业务层
目标
- 编写UserDao代码
- 编写UserService代码
步骤
UserDao
通过用户名和密码查询一个用户
UserService
业务类直接调用DAO类中相应的方法返回用户对象即可
代码
UserDao
新的知识点,如果访问mybatis的方法有2个以上的参数,必须使用@Param(“参数名”)
package com.itheima.dao;import com.itheima.entity.User;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;/*** 用户的数据访问类*/
public interface UserDao {/*** 通过用户名和密码查询1个用户* 如果2两个以上的参数:必须指定参数的名字,使用@Param("参数名")*/@Select("SELECT * FROM `user` WHERE username=#{username} AND PASSWORD=#{password}")User findUser(@Param("username") String username, @Param("password") String password);
}
UserDaoImpl实现类
package com.itheima.dao.impl;import com.itheima.dao.UserDao;
import com.itheima.entity.User;
import com.itheima.utils.SqlSessionUtils;
import org.apache.ibatis.session.SqlSession;/*** DAO的实现类*/
public class UserDaoImpl implements UserDao {@Overridepublic User findUser(String username, String password) {//1.获取会话对象SqlSession session = SqlSessionUtils.getSession();//2.得到DAO的代理对象UserDao userDao = session.getMapper(UserDao.class);//3.调用接口中方法User user = userDao.findUser(username, password);//4.关闭会话session.close();//5.返回查询的结果return user;}
}
测试DAO
package com.itheima.test;import com.itheima.dao.UserDao;
import com.itheima.dao.impl.UserDaoImpl;
import com.itheima.entity.User;
import org.junit.Test;//alter+enter自动导入junit
public class TestUserDao {@Testpublic void testUser() {//多态UserDao userDao = new UserDaoImpl();User user = userDao.findUser("Jack", "123");System.out.println(user);}
}
UserService接口
package com.itheima.service;import com.itheima.entity.User;/*** 业务类*/
public interface UserService {/*** 登录的方法*/User login(String username, String password);
}
UserServiceImpl实现类
package com.itheima.service.impl;import com.itheima.dao.UserDao;
import com.itheima.dao.impl.UserDaoImpl;
import com.itheima.entity.User;
import com.itheima.service.UserService;/*** 业务层实现类*/
public class UserServiceImpl implements UserService {//调用DAO方法private UserDao userDao = new UserDaoImpl();@Overridepublic User login(String username, String password) {return userDao.findUser(username, password);}
}
16. 登录案例part3:Servlet
目标
- 登录的LoginServlet
- 登录成功的SuccessServlet
LoginServlet
步骤
- 解决汉字乱码问题
- 得到用户提交的用户名和密码
- 调用业务层实现登录操作
- 如果用户名不为空表示登录成功
- 把当前的用户信息放在请求域中,以后放在会话域中
- 转发到success
- 如果登录失败重定向到failure.html页面
代码
package com.itheima.servlet;import com.itheima.entity.User;
import com.itheima.service.UserService;
import com.itheima.service.impl.UserServiceImpl;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@WebServlet("/login")
public class LoginServlet extends HttpServlet {//创建业务层private UserService userService = new UserServiceImpl();protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//设置汉字乱码的问题request.setCharacterEncoding("utf-8");//1. 获取用户名和密码String username = request.getParameter("username");String password = request.getParameter("password");//2. 调用业务层实现登录User user = userService.login(username, password);//3. 如果登录成功跳转到成功页面if (user != null) {//把用户信息放在请求域中request.setAttribute("user", user);//转发到另一个页面,指定跳转的地址successrequest.getRequestDispatcher("success").forward(request, response);}//4. 如果登录失败跳转到失败页面else {response.sendRedirect("failure.html");}}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doPost(request, response);}
}
SuccessServlet
步骤
- 设置响应的类型和字符集
- 得到打印流对象
- 从请求域中取出用户信息
- 输出登录成功的信息
代码
package com.itheima.servlet;import com.itheima.entity.User;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;/*** 显示登录成功*/
@WebServlet("/success")
public class SuccessServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType("text/html;charset=utf-8");PrintWriter out = response.getWriter();//1.从请求域中获取用户的信息User user = (User) request.getAttribute("user");//2.打印到浏览器上out.print("<h1>欢迎您!" + user.getUsername() + "</h1>");}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doPost(request, response);}
}
整个项目结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rEsRDOoJ-1598790831984)(assets/image-20200828164833906.png)]
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns=""xmlns:xsi=""xsi:schemaLocation=" .xsd"version="4.0"><welcome-file-list><welcome-file>login.html</welcome-file></welcome-file-list>
</web-app>
17. 服务器端代码的调试
-
查看错误信息
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l52PhPIQ-1598790831986)(assets/image-20200828165226580.png)]
-
设置服务器上Java代码的断点
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5jTC6aSb-1598790831988)(assets/image-20200828165337510.png)]
-
在调试模式下运行
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1JXQEup7-1598790831989)(assets/image-20200828165415377.png)]
学习总结
- 能够理解HTTP协议请求内容
- 请求行
- 请求头
- 请求体:POST才有请求体
- 能够使用Request对象获取HTTP协议请求内容
请求方法 | 功能描述 |
---|---|
String getHeader(String headName) | 通过请求头的名字获取值 |
String getMethod() | 获取请求的方法GET或POST |
String getRequestURI() | 获取请求的URI |
方法名 | 描述 |
---|---|
String getParameter(String name) | 通过参数名获取参数值 |
String[] getParameterValues(String name) | 通过参数名获取一组参数值 |
Map<String,String[]> getParameterMap() | 获取所有的参数名和值,封装成Map对象 |
- 能够处理HTTP请求参数的乱码问题
GET: 没有乱码
POST:
setCharacterEncoding("utf-8")
- 能够使用Request域对象
request与域有关的方法 | 作用 |
---|---|
Object getAttribute(“键”) | 通过键获取值 |
void setAttribute(“键”,Object 数据) | 设置键和值 |
void removeAttribute(“键”) | 删除键和值 |
- 能够使用Request对象做请求转发
转发的方法:
request.getRequestDispatcher("地址").forward(request, response)
重定向的方法:
response.sendRedirect("地址")
- 能够完成登录案例
更多推荐
WEB阶段2:http协议请求对象【转发重定向请求参数乱码问题】BeanUtils使用软件开发三层架构项目结构
发布评论