Servlet进阶知识笔记
URL和URI的区别
- URL统一资源定位符,表示Web应用对外暴露的访问地址
示例: http://www.imooc.com/index.html
URI统一资源标示符,表示Web应用资源的访问路径
示例:/index.html
HTTP请求的结构
- HTTP请求包含三部分:请求行、请求头、请求体
请求行由请求方法【POST】,请求URI【/chapter01/login.html】和HTTP协议及版本【HTTP/1.1】组成
POST /chapter01/login.html HTTP/1.1
请求头
Accept: image/jpeg, application/x-ms-application, …,*/*Referer: http://localhost:8088/chaptero1/user/register.html?code=100&time=123123
Accept-Language: zh-CN
User-Agent: Mozilla/4.0(compatible; MSIE 8.0; Windows NT 6.1;Content-Type: application/x-www-form-urlencoded
Host: localhost:8088
Content-Length: 112Connection: Keep-AliveCache-Control: no-cache
Cookie:JESSIONID=23DE2343E23ED3F22D8669D2434AC23D
请求体,Post方法时的传递参数信息。
name=imooc&password=123456&realName=imooc
利用请求分辨多端应用
- 开发多端应用原理: 读取请求头中的User-Agent并判断字符串
@WebServlet("/ua")
public class UserAgentServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String ua = request.getHeader("User-Agent");
String output = "";
if(ua.toLowerCase().indexOf("windows nt") != -1){
output = "<h1>这是PC端的页面</h1>";
}else if(ua.toLowerCase().indexOf("android") != -1 || ua.toLowerCase().indexOf("iphone") != -1){
output = "<h1>这是移动端的页面</h1>";
}
response.setContentType("text/html;charset=utf-8");
response.getWriter().println(output);
}
}
HTTP响应的结构
- HTTP响应包含三部分:响应行、响应头、响应体
响应行由报文协议及版本【HTTP/1.1】和状态码及状态描述【200 OK】组成
响应头
Server: Apache-Coyote/1.1
Content-Type: text/html
Transfer-Encoding:chunked
Date: Tue,9 Oct 2018 13:45:23 GMT
响应体. 服务器生成的Html数据代码片段
<html><head>
<title>我是响应体</title></head>
</html> - HTTP常见状态码
200: 服务器处理成功
404: 无法找到资源
500: 内部服务器错误
403: 服务器拒绝访问
400: 无效的请求
401: 未经过授权
503: 服务器超负载或正停机维护,无法处理请求
ContentType的作用
- ContentType决定浏览器采用何种方式对响应体进行处理
text/plain: 纯文本
text/html: HTML文档
text/xml: XML文档
application/x-msdownload:
需要下载的资源
image/jpeg / image/gif / image/… : 图片资源
请求转发与响应重定向
- 多个Servlet之间跳转有两种方式:
request.getRequestDispatcher().forward() – 请求转发
response.sendRedirect() – 响应重定向 - 请求转发
请求转发是服务器跳转,只会产生一次请求
请求转发语句是: request.getRequestDispatcher().forward()
由于是在服务器内部不同的servlet进行跳转,需要使用一样的提交方法
并且由于浏览器只发出了一次请求,URL的地址不会变 - 响应重定向
重定向则是浏览器端跳转,会产生两次请求
响应重定向语句是: response.sendRedirect()
在第一次浏览器发出请求后,服务器会给浏览器发出一个响应,浏览器会根据这个响应自动的用Get方法发出一个请求,服务器会根据这个新的请求返回响应,所以是浏览器发出了两个请求给不同的服务器里的Servlet。 - 设置请求自定义属性
请求允许创建自定义属性
设置请求属性: request.setAttribute(属性名,属性值)
获取请求属性:Object attr = request.getAttribute(属性名)
由于请求在响应返回给浏览器时就销毁,请求自定义属性只能在请求转发方法使用
@WebServlet("/login")
public class CheckLoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
if(username.equals("admin") && password.equals("123456")){
System.out.println("用户登录成功");
request.setAttribute("username", username);
request.getRequestDispatcher("/index").forward(request, response);
} else {
System.out.println("用户登录失败");
}
}
}
@WebServlet("/index")
public class IndexServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
String username = (String)request.getAttribute("username");
PrintWriter out = response.getWriter();
out.println("<h1>我是网站首页</h1>" + username);
}
}
浏览器中的Cookie
- Cookie (小甜饼)是浏览器保存在本地的文本内容
Cookie默认域名绑定,只有当前域名下的程序才能读取数据
Cookie具有时效性,Cookie会伴随请求头发送给服务器
Cookie的时效性有两种情况:
默认Cookie有效期与当前浏览器进程绑定
设置过期时间后,Cookie过期后才会失效
可以通过request.getCookies()获取所有的cookie
可以通过cookie.setMaxAge()设置cookie的有效期,以秒为单位
@WebServlet("/cookie/random")
public class RandomServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Integer random = new Random().nextInt(10000);
Cookie cookie = new Cookie("random", String.valueOf(random));
cookie.setMaxAge(60*60*24);
response.addCookie(cookie);
response.setContentType("text/html;charset=utf-8");
response.getWriter().println("<h1>随机数是" + random + "已生成</h1>");
}
}
@WebServlet("/cookie/show")
public class CookieServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Cookie[] cookies = request.getCookies();
response.setContentType("text/html;charset=utf-8");
if(cookies == null){
response.getWriter().println("未包含任何Cookie数据");
return;
}
Integer random = -1;
for(Cookie cookie : cookies){
if(cookie.getName().equals("random")){
random = Integer.parseInt(cookie.getValue());
}
}
response.getWriter().println("name=random的cookie值为:" + random);
}
}
Session用户会话
- Session(用户会话)用于保存与“浏览器窗口”对应的数据
Session的数据存储在Tomcat服务器的内存中,具有时效性
Session通过浏览器Cookie的Sessionld值提取用户数据
request.getSession() – 获取Session对象
get|set|/removeAttribute() – 获取|设置|删除Session属性
setMaxlnactivelnterval() – 设置Session超时时间
@WebServlet("/session/random")
public class RandomServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Integer random = new Random().nextInt(10000);
response.setContentType("text/html;charset=utf-8");
HttpSession session = request.getSession();
session.setAttribute("random", random);
response.getWriter().println("<h1>随机数是" + random + "已生成</h1>");
}
}
@WebServlet("/session/show")
public class SessionServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
HttpSession session = request.getSession();
Integer random = (Integer)session.getAttribute("random");
response.getWriter().println("name=random的cookie值为:" + random);
}
}
ServletContext和三大作用域对象
- ServletContext(Servlet上下文对象),是Web应用全局对象
一个Web应用只会创建一个ServletContext对象
ServletContext随着Web应用启动而自动创建
案例:保存不变的页脚信息,减少每次响应返回的页面数据
@WebServlet("/servletcontext/init")
public class ServletContextServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext servletContext = request.getServletContext();
servletContext.setAttribute("copyright", "京公网安备11000002000001号 京ICP证030173号 ©2022 Baidu");
response.setContentType("text/html;charset=utf-8");
response.getWriter().println("ServletContext已初始化");
}
}
@WebServlet("/servletcontext/index")
public class IndexServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
ServletContext context = request.getServletContext();
String copyright = (String)context.getAttribute("copyright");
PrintWriter out = response.getWriter();
out.println(copyright);
}
}
- 三大作用域对象
HttpServletRequest - 请求对象(返回响应时销毁)
HttpSession - 用户会话对象(关闭浏览器cookie销毁时,或设置时间到时销毁)
ServletContext - Web应用全局对象(Web应用程序关闭或重启时销毁)
解决中文乱码的问题
- 发送方与接收方对数据使用不同的字符集解析就会产生乱码
解决乱码的思路是保证浏览器与服务器统一为UTF-8编码即可
在Servlet中请求与响应都需要设置UTF-8字符集
@WebServlet("/encoding/search")
public class SearchServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String keyword = request.getParameter("keyword");
System.out.println(keyword);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
String keyword = request.getParameter("keyword");
System.out.println(keyword);
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="encoding/search" method="post">
<input name="keyword"/>
<input type="submit"/>
</form>
</body>
web.xml常用配置
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
- Servlet通配符映射及初始化参数
http://www.imooc.com/search?cid=785
http://www.imooc.com/class/785
http://www.imooc.com/785.class
<servlet>
<servlet-name>pattern</servlet-name>
<servlet-class>com.example.servlet.PatternServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>pattern</servlet-name>
<url-pattern>/class/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>pattern</servlet-name>
<url-pattern>*.class</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>pattern</servlet-name>
<url-pattern>/class/*.class</url-pattern>
</servlet-mapping>
<error-page>
<error-code>404</error-code>
<location>/error/404.html</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/error/500.html</location>
</error-page>
启动时加载Servlet
- web.xml使用<load-on-startup>设置启动加载
<load-on-startup>0~9999</load-on-startup>
启动时加载在工作中常用于系统的预处理
可以在预处理中设置键值对参数
<servlet>
<servlet-name>initTable</servlet-name>
<servlet-class>com.example.servlet.startup.InitTableServlet</servlet-class>
<init-param>
<param-name>database</param-name>
<param-value>db01</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet>
<servlet-name>import</servlet-name>
<servlet-class>com.example.servlet.startup.ImportServlet</servlet-class>
<init-param>
<param-name>file</param-name>
<param-value>c:/tmp/demo.txt</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
public class InitTableServlet extends HttpServlet {
@Override
public void init(ServletConfig config) throws ServletException {
String database = config.getInitParameter("database");
System.out.println("正在向" + database + "创建数据表...");
}
}
public class ImportServlet extends HttpServlet {
@Override
public void init(ServletConfig config) throws ServletException {
String file = config.getInitParameter("file");
System.out.println("正在导入" + file + "文件数据...");
}
}
Java Web的打包与发布
- Java Web应用采用war包进行发布
发布路径为:{TOMCAT_HOME}/webapps
利用Maven实现war包导出
Scope属性作用
compile: 默认值,依赖组件作用于所有阶段
provided: 依赖组件仅作用在编译与测试阶段
runtime: 依赖组件仅作用在测试与运行阶段
test: 依赖组件仅作用在测试阶段
system: 本地Jar文件仅作用在编译与测试阶段
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>web-servlet</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
<version>4.0.0</version>
</dependency>
</dependencies>
<build>
<finalName>web-servlet</finalName>
</build>
</project>
- 发布:
把生成的war包复制到Tomcat文件夹下的webapps目录
在bin中点击startup.batt运行Tomcat即可
去除Tomcat强制的文件名上下文:
在Tomcat文件夹下的conf目录的server.xml文件中的<host>标签中添加
<Context docBase=“web-servlet” path=“/”/>标签配置