3. Servlet + Request + Response
3.1 中文乱码解决方案
请求时的乱码:
Tomcat 8.5 前端数据发送的是utf-8,后端接收也是utf-8
Tomcat 7 以及以下的版本 前端数据发送的是utf-8,由于Tomcat编码使用的是ISO08859-1,此时数据需要重新转码。
为了安全起见:
设置请求对象的编码集为utf-8
//request.setCharacterEncoding("utf-8");
响应时的乱码:
//response.setContentType("text/html;charset=utf-8");
或者
//response.setHeader("content-type","text/html;charset=utf-8");
3.2 重定向、转发(重点)
3.2.1 重定向
流程:
- 用户通过浏览器发送一个请求;
- web服务器接收到这个请求;
- 服务器先发给用户一个302状态码,并且设置重定向路径;
- 浏览器发现302状态码后,会自动加载服务器设置的路径;
- 此时,浏览器才会真正到达服务器指定的路径。
本质:两个页面的跳转
//重定向 响应
response.sendRedirect("target.html");
重定向的特征:
- 重定向的过程是浏览器的行为;
- 实际上浏览器做了两次请求;
- 重定向之后,会导致不可逆的数据丢失(上一次的Request对象会丢失);
- 重定向时,浏览器的URL路径在变化;
- 重定向可以指向任意的网络资源。
3.2.2 转发
流程:
- 用户通过浏览器发送Http请求到服务器;
- 服务器接处理当前请求;
- 服务器调用内部的处理方式处理该请求;
- 最终通过处理方式,把响应给用户;
TestServlet1
package com.forward;
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("/TestServlet1")
public class TestServlet1 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("用户请求了TestServlet1");
//在当前的servlet中设置了一个属性,保存到request对象中
req.setAttribute("name","耶啵");
//通过requestServlet对象,
// 转发数据到其他的web应用程序中,
// 并且使用forward方法把当前的request对象和response对象带过去
req.getRequestDispatcher("TestServlet2").forward(req,resp);
}
}
TestServlet2
package com.forward;
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 javax.sound.midi.Soundbank;
import java.io.IOException;
@WebServlet("/TestServlet2")
public class TestServlet2 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
//getAttribute() 通过键值获取value值
Object name = req.getAttribute("name");
resp.getWriter().append("转发到TestServlet2中的内容:" + name);
}
}
转发的特征:
- 重定向的过程是服务器的行为;
- 浏览器发送了一次请求;
- 转发会带有request对象;
- 浏览器URL路径不变;
- 转发只能在同一个服务器中。
4. URL的匹配原则
用户在浏览器中请求:
http://localhost:8080/forward_redirect_war_exploded/TestServlet1
- 用户使用的是http协议;
- 连接主机地址是 localhost 或 本机ip地址 127.0.0.1
- 端口号 8080
- 申请的资源 forward_redirect_war_exploded/TestServlet1
- forward_redirect_war_exploded 整个Web application
- 在当前的Web application申请的一个 TestServlet1 的资源
申请资源的时候会被Tomcat捕捉到,然后立刻匹配web.xml文件:
1.找到 servlet-mapping,子标签 url-pattern 匹配,匹配之后;
2.使用servlet-mapping中的子标签 servlet-name 确定当前的servlet名字;
3.找到servlet标签,使用子标签 servlet-name 与步骤2中servlet-name进行匹配;
4.通过名字匹配servlet后,可以找到关键的类 servlet-class ,会有当前对应的字节码文件,可以执行servlet
url 的匹配规则:
1.精准匹配
- /资源的名称
例如:@WebServlet("/LoginServlet")
@WebServlet(value="/LoginServlet")
@WebServlet(urlpatterns={"/LoginServlet","/test.do","/test.action"}) - 模糊匹配
*.do
.action
要求以指定的结尾完成匹配,例如 /
模糊匹配
package com.fuzzy;
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("*.do")
//@WebServlet("*.action")
@WebServlet("/*")
public class FuzzyServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().append("我不困");
}
}
5. ServletContext对象(重点)
ServletContext 是 servlet 的上下文对象
是项目中唯一一个可以共享的对象
在一个项目中,servlet中间没有关系
常用的七个方法:
- getServletContext() 实例化当前上下文对象
- setAttribute(String s, Object o) 对比上下文设置数据,可以设置字符串,也可以设置对象
- getAttribute(String s) 通过上下文对象获取数据(所有的servlet包括前端页面都可以获取数据)
- getRealPath("/") 获取当前项目的实际目录
- getServerInfo() 获取当前服务器的版本信息
- getContextPath() 获取当前项目的根目录(一般用在前后端联系)
package com.servletcontext;
import javax.servlet.ServletContext;
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("/ContextServlet")
public class ContextServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//实例化当前上下文对象
ServletContext servletContext = req.getServletContext();
//对当前上下文设置数据,可以设置字符串,也可以设置对象
servletContext.setAttribute("msg","wawa");
servletContext.setAttribute("Person",new Person("小璇",23));
}
}
package com.servletcontext;
import javax.servlet.ServletContext;
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("/ContextServlet2")
public class ContextServlet2 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//实例化当前上下文对象
ServletContext servletContext = req.getServletContext();
//获取当前项目的实际目录
System.out.println(servletContext.getRealPath("/"));
//获取当前服务器的版本信息
System.out.println(servletContext.getServerInfo());
//获取当前项目的根目录 (重要) 一般用在前后端联系
System.out.println(servletContext.getContextPath());
//通过上下文对象获取数据(所有servlet包括前端页面都可以获取数据)
Object msg = servletContext.getAttribute("msg");
Person person = (Person) servletContext.getAttribute("Person");
System.out.println(msg);
System.out.println(person);
}
}
6. ServletRequest对象
6.1 Request的介绍
用户在访问服务器时,会自动生成一个请求对象,这个请求对象包括了所有的http请求头
通过Tomcat 会把这个请求头变成一个对象 这个对象就是request
6.2 api
-
getRequestURL() 请求时候完整的url(统一资源定位法)
-
getRequestURI() 请求资源的部分url(统一资源标识符)
-
getQueryString() 请求的参数部分
-
getRemoteAddr() 发送请求的客户主机ip地址
-
getRemoteHost() 发送请求的客户的完整的主机名
-
getRemotePort() 发送请求的客户机的端口号
-
getLocalAddr() 返回web服务器的ip地址
-
getRemoteUser() 主机名字
7. ServletResponse对象
7.1 Response的介绍
响应:把数据发送给当前客户端的一种方式。servlet容器会自动创建一个Response对象。
7.2 API
- setContentType(“text/html;utf-8”) 设置编码格式
- getWriter() 获取字符输出流
- serRedirect() 重定向