JavaWeb笔记:第06章 Tomcat | Servlet | HTTP协议 | request | response | ServletContext | Cookie | Session|JSP
- 1.web相关概念回顾
- 2. Tomcat——web服务器软件
-
-
- 2.1 Tomcat安装&卸载&使用&配置
- 2.2 IDEA与tomcat的相关配置
- 3. Servlet——server applet
-
-
- 3.1 Servlet概念
- 3.2 Servlet快速入门
- 3.3 Servlet 执行原理
- 3.4 Servlet的生命周期
- 3.5 新的Servlet标准—— Servlet3.0
- 3.6 Servlet的体系结构
- 3.7 Servlet相关配置
- 4. HTTP协议
-
-
- 4.1 HTTP概念&特点
- 4.2 请求消息数据格式
- 4.3 响应消息数据格式
- 5. request对象 & response对象
-
-
- 5.1 request和response的作用
- 5.2 request对象
-
-
- 5.2.1 request对象继承体系结构
- 5.2.2 request的功能——获取请求消息数据&其他功能
-
- 5.2.2.1 获取请求消息数据
- 5.2.2.2 其他功能
- 5.2.3 案例:用户登录
-
- 5.2.3.1 案例需求
- 5.2.3.2 分析&开发步骤
- 5.3 response对象
-
-
- 5.3.1 response对象功能——设置响应消息
- 5.3.2 案例一:完成重定向 & 服务器输出字符数据到浏览器 & 服务器输出字节数据到浏览器
-
- 1. 完成重定向
- 2. 服务器输出字符数据到浏览器
- 3. 服务器输出字节数据到浏览器
- 4. 资源路径写法
- 5. 实现验证码
- 6. ServletContext对象:
-
-
- 6.1 概念 & 获取ServletContext对象
- 6.2 ServletContext对象的功能
- 6.3 案例
- 7. 会话技术——Cookie & Session
-
-
- 7.1 Cookie
-
-
- 7.1.1 Cookie的概念 & 代码入门
- 7.1.2 cookie实现原理
- 7.1.3 cookie的细节
- 7.1.3 Cookie的特点和作用
- 7.1.4 案例:记住上一次访问时间
- 7.2 JSP 入门学习
- 7.3 Session
-
-
- 7.3.1 Session概念 & 快速入门
- 7.3.2 Session原理
- 7.3.3 Session的细节
- 7.3.4 session的特点
- 7.3.5 案例:验证码
- 8. JSP
-
-
- 8.1 JSP作用 & JSP指令
- 8.2 JSP 指令分类
-
-
- 8.2.1 page指令
- 8.2.2 include指令
- 8.2.3 taglib指令
- 8.2.4 jsp注释 & jsp内置对象
说明:本内容整理自B站黑马程序员Java web课程视频及文档>>B站黑马程序员Java web课程视频
1.web相关概念回顾
1. 软件架构
1. C/S:客户端/服务器端
2. B/S:浏览器/服务器端
2. 资源分类
1. 静态资源:所有用户访问后,得到的结果都是一样的,称为静态资源.
静态资源可以直接被浏览器解析。如: html,css,JavaScript
2. 动态资源:每个用户访问相同资源后,得到的结果可能不一样。称为动态资源。
动态资源被访问后,需要先转换为静态资源,在返回给浏览器。如:servlet/jsp,php,asp....
B/S架构:浏览器/服务器端 |
3. 网络通信三要素
1. IP:电子设备(计算机)在网络中的唯一标识。
2. 端口:应用程序在计算机中的唯一标识。 0~65536
3. 传输协议:规定了数据传输的规则
1. 基础协议:
1. tcp:安全协议,三次握手。 速度稍慢
2. udp:不安全协议。 速度快
4.web服务器软件
1.服务器:安装了服务器软件的计算机
2.服务器软件:接收用户的请求,处理请求,做出响应
3.web服务器软件:接收用户的请求,处理请求,做出响应。
1.在web服务器软件中,可以部署web项目,让用户通过浏览器来访问这些项目
2.web服务器软件也被称为web容器,动态资源运行在web容器中
4.常见的java相关的web服务器软件:
1.webLogic:oracle公司,大型的JavaEE服务器,支持所有的JavaEE规范,收费的。
2. webSphere:IBM公司,大型的JavaEE服务器,支持所有的JavaEE规范,收费的。
3.JBOSS:JBOSS公司的,大型的JavaEE服务器,支持所有的JavaEE规范,收费的。
4.Tomcat:Apache基金组织,中小型的JavaEE服务器,仅仅支持少量的JavaEE规范servlet/jsp。开源的,免费的。
* JavaEE:Java语言在企业级开发中使用的技术规范的总和,一共规定了13项大的规范
2. Tomcat——web服务器软件
2.1 Tomcat安装&卸载&使用&配置
5.Tomcat:web服务器软件
1. 下载:http://tomcat.apache.org/
查看Tomcat文件目录:
apache-tomcat-8.5.31安装包文件目录 |
2. 安装:解压压缩包即可。
注意:安装目录建议不要有中文和空格
3. 卸载:删除目录就行了
4. 启动:
bin/startup.bat ,双击运行该文件即可
访问:浏览器输入:http://localhost:8080 回车访问自己
http://别人的ip:8080 访问别人
可能遇到的问题:
1. 黑窗口一闪而过:
原因: 没有正确配置JAVA_HOME环境变量
解决方案:正确配置JAVA_HOME环境变量
2. 启动报错:
1. 暴力:找到占用的端口号,并且找到对应的进程,杀死该进程
netstat -ano
2. 温柔:修改自身的端口号
在conf/server.xml文件下修改:
一般会将tomcat的默认端口号修改为80。80端口号是http协议的默认端口号。
好处:在访问时,就不用输入端口号
3.启动(安装)成功现象:在浏览器输入http://localhost:8080可看到如下Tomcat自带的项目的页面
Tomcat自带的项目的页面(显示此页面则证明Tomcat安装成功) |
5. 关闭:
1. 正常关闭(推荐):
bin/shutdown.bat
ctrl+c
2. 强制关闭(不推荐):
点击启动窗口的×
6. 配置:
1.部署项目的方式:
1. 方式一:直接将项目(如此处的hello项目)放到webapps目录下即可。
1、http://localhost:8080/hello中的/hello称为项目的访问路径,也称虚拟目录
2、简化部署:将项目打成一个war包,再将war包放置到webapps目录下。
war包会自动解压缩
方式一缺点:服务器只能访问webapps目录下的资源
2. 方式二:配置conf/server.xml文件
在标签体中配置
docBase:项目存放的路径
path:虚拟目录
方式二缺点:conf/server.xml为Tomcat的核心配置文件,修改过程中可能导致错误(缺乏安全性)
3. 方式三(热部署——不用重启服务器就可以生效):在conf\Catalina\localhost创建任意名称的xml文件。在文件中编写
虚拟目录:xml文件的名称 ——xml文件的名称就是虚拟目录
例子:在hello.xml中加入
2.项目部署说明:
项目分为静态项目和动态项目,静态项目和动态项目的目录结构是存在差异的:
目录结构
java动态项目的目录结构:
-- 项目的根目录
-- WEB-INF目录:
-- web.xml:web项目的核心配置文件
-- classes目录:放置字节码文件的目录
-- lib目录:放置依赖的jar包
7.将Tomcat集成到IDEA中,并且创建JavaEE的项目,部署项目。视频链接如下:
https://www.bilibili.com/video/BV1qv4y1o79t?p=230&spm_id_from=pageDriver&vd_source=60482f480b98c4a8ef39f39be38a8b56
2.2 IDEA与tomcat的相关配置
1. IDEA会为每一个tomcat部署的项目单独建立一份配置文件
查看控制台的log:Using CATALINA_BASE: "C:\Users\fqy\.IntelliJIdea2018.1\system\tomcat\_itcast"(此目录下包含 当前项目对于Tomcat的配置)
2. 工作空间项目 和 tomcat部署的web项目
tomcat真正访问的是“tomcat部署的web项目”,"tomcat部署的web项目"对应着"工作空间项目" 的web目录下的所有资源
WEB-INF目录下的资源不能被浏览器直接访问。
3. 断点调试:使用"小虫子"启动 ——dubug 启动
3. Servlet——server applet
3.1 Servlet概念
Servlet——server applet概念:运行在服务器端的小程序
Servlet就是一个接口,定义了Java类被浏览器访问(tomcat识别)到的规则。
将来我们自定义一个Java类,这个Java类没有主方法,要依赖于Tomcat服务器才能运行
要让服务器能识别这个Java类,就需要实现Servlet接口、并复写接口方法
Servlet就是一个接口,定义了Java类被浏览器访问(tomcat识别)到的规则 |
3.2 Servlet快速入门
Servlet快速入门:
1. 创建JavaEE项目
2. 定义一个类,实现Servlet接口
public class ServletDemo1 implements Servlet
详细代码:
package cn.itcast.web.servlet;
import javax.servlet.*;
import java.io.IOException;
/**
* Servlet快速入门
*/
public class ServletDemo1 implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
//提供服务的方法
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("Hello Servlet");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
3. 实现接口中的抽象方法
4. 配置Servlet
在web.xml中配置:
demo1
cn.itcast.web.servlet.ServletDemo1
demo1
/demo1
5.用浏览器执行Java类:
在浏览器中输入网址localhost:8080/dome1 并按下回车即可运行上述Java类
运行成功可在idea的控制台上打印Hello Servlet
3.3 Servlet 执行原理
执行原理(Servlet识别Java类并执行的原理):
1. 当服务器接受到客户端浏览器的请求后,会解析请求URL路径,获取访问的Servlet的资源路径
2. 查找web.xml文件,是否有对应的标签体内容与资源路径一致
3. 如果有,则再找到对应的全类名
4. tomcat会将字节码文件加载进内存,并且创建其对象
5. 调用其方法
Servlet识别并执行Java类的原理 |
3.4 Servlet的生命周期
Servlet中的方法——对应Servlet的生命周期:
1. 被创建:执行init方法,只执行一次
1.Servlet什么时候被创建?
1.默认情况下,第一次被访问时,Servlet被创建
2.也可以配置执行Servlet的创建时机。
在标签下配置
1. 第一次被访问时,创建
的值为负数
2. 在服务器启动时,创建
的值为0或正整数
2.注:Servlet的init方法,只执行一次,说明一个Servlet在内存中只存在一个对象,Servlet是单例的
导致的问题:多个用户同时访问时,可能存在线程安全问题。
解决方法:尽量不要在Servlet中定义成员变量。即使定义了成员变量,也不要修改值
2. 提供服务:执行service方法,执行多次
每次访问Servlet时,Service方法都会被调用一次。
3. 被销毁:执行destroy方法,只执行一次
Servlet被销毁时执行。服务器关闭时,Servlet被销毁
注意:只有服务器正常关闭时,才会执行destroy方法。
destroy方法在Servlet被销毁之前执行,一般用于释放资源
例程:
1.配置web.xml文件:
demo2
cn.itcast.web.servlet.ServletDemo2
-5
demo2
/demo2
2.Java类:
package cn.itcast.web.servlet;
import javax.servlet.*;
import java.io.IOException;
/**Servlet的方法 */
public class ServletDemo2 implements Servlet {
private int age = 3;
/**
* 初始化方法
* 在Servlet被创建时,执行。只会执行一次
* @param servletConfig
* @throws ServletException
*/
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("init.....");
}
/**
* 获取ServletConfig对象
* ServletConfig:Servlet的配置对象
* @return
*/
@Override
public ServletConfig getServletConfig() {
return null;
}
/**
* 提供服务方法
* 每一次Servlet被访问时,执行。执行多次
* @param servletRequest
* @param servletResponse
* @throws ServletException
* @throws IOException
*/
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("service.....");
int number = 3;
}
/**
* 获取Servlet的一些信息,版本,作者等等。。
* @return
*/
@Override
public String getServletInfo() {
return null;
}
/**
* 销毁方法
* 在服务器正常关闭时,执行,执行一次。
*/
@Override
public void destroy() {
System.out.println("destroy.....");
}
}
3.5 新的Servlet标准—— Servlet3.0
新的Servlet标准—— Servlet3.0:
视频链接:https://www.bilibili.com/video/BV1qv4y1o79t?p=236&spm_id_from=pageDriver&vd_source=60482f480b98c4a8ef39f39be38a8b56
好处:
Servlet3.0支持注解配置。可以不需要web.xml了
步骤:
1. 创建JavaEE项目,选择Servlet的版本3.0以上,可以不创建web.xml
2. 定义一个类,实现Servlet接口
3. 复写方法
例程(已包含第四个步骤):
package cn.itcast.web.servlet;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;
@WebServlet(urlPatterns="/demo2")
public class ServletDemo implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("Servlet3.0来了.....");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
4. 在类上使用@WebServlet注解,进行配置
1.@WebServlet("资源路径")或@WebServlet(urlPatterns="/demo2")
2.注解@WebServlet的源码:
package javax.servlet.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WebServlet {
String name() default "";//相当于
String[] value() default {};//代表urlPatterns()属性配置
String[] urlPatterns() default {};//相当于
int loadOnStartup() default -1;//相当于
WebInitParam[] initParams() default {};
boolean asyncSupported() default false;
String smallIcon() default "";
String largeIcon() default "";
String description() default "";
String displayName() default "";
}
3.6 Servlet的体系结构
6. Servlet的体系结构
Servlet -- 接口
|
GenericServlet -- 抽象类
|
HttpServlet -- 抽象类
GenericServlet:将Servlet接口中其他的方法做了默认空实现,只将service()方法作为抽象
将来定义Servlet类时,可以继承GenericServlet,实现service()方法即可
注:也可以对其他方法进行实现,默认只用复写service()方法
HttpServlet:对http协议的一种封装,简化操作
若有HTTP的相关操作,可继承HttpServlet并复写doGet/doPost方法即可
HttpServlet的使用:
1. 定义类继承HttpServlet
2. 复写doGet/doPost方法(不用复写service()方法)
|
HttpServlet例程:
package cn.itcast.web.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;
@WebServlet("/demo3")
public class ServletDemo3 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doGet....");//浏览器直接请求是get方式
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doPost...");
}//可以通过表单(设置method属性为post)来完成post的请求
}
3.7 Servlet相关配置
7. Servlet相关配置
1. urlpartten:Servlet访问路径
1. 一个Servlet可以定义多个访问路径 : @WebServlet({"/d4","/dd4","/ddd4"})
2. 路径定义规则:
1. /xxx:路径匹配
2. /xxx/xxx:多层路径,目录结构
3. /* (匹配的优先级很低)
4. *.do:扩展名匹配
4. HTTP协议
4.1 HTTP概念&特点
概念:Hyper Text Transfer Protocol 超文本传输协议
传输协议:定义了,客户端和服务器端通信时,发送数据的格式
特点:
1. HTTP协议是基于TCP/IP的高级协议
2. HTTP协议默认端口号:80
3. HTTP协议基于请求/响应模型的:一次请求对应一次响应
4. HTTP协议是无状态的:每次请求之间相互独立,不能交互数据
历史版本:1.0和1.1
1.0和1.1的区别之一:
1.0:每一次请求响应都会建立新的连接
1.1:复用连接
4.2 请求消息数据格式
请求消息数据格式——请求消息由请求行、请求头、请求空行、请求体组成
1. 请求行
请求行格式:请求方式 请求url 请求协议/版本
例子:GET /login.html HTTP/1.1
请求方式:
HTTP协议有7中请求方式,常用的有2种
GET:
1. 请求参数在请求行中,在url后。
2. 请求的url长度有限制的
3. 不太安全
POST:
1. 请求参数在请求体中
2. 请求的url长度没有限制的
3. 相对安全
2. 请求头:客户端浏览器告诉服务器一些信息
请求头名称: 请求头值
常见的请求头:
1. User-Agent:浏览器告诉服务器,我访问你使用的浏览器版本信息
可以在服务器端获取该头的信息,解决浏览器的兼容性问题
2. Referer:http://localhost/login.html
告诉服务器,我(当前请求)从哪里来?
作用:
1. 防盗链:
2. 统计工作:
3. 请求空行
空行,就是用于分割POST请求的请求头,和请求体的
4. 请求体(正文):
封装POST请求消息的请求参数的
请求消息字符串格式:
POST /login.html HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: http://localhost/login.html
Connection: keep-alive
Upgrade-Insecure-Requests: 1
username=zhangsan
4.3 响应消息数据格式
2. 响应消息:服务器端发送给客户端的数据
* 数据格式:
1. 响应行
1. 组成:协议/版本 响应状态码 状态码描述
2. 响应状态码:服务器告诉客户端浏览器本次请求和响应的一个状态。
1. 状态码都是3位数字
2. 分类:
1. 1xx:服务器就收客户端消息,但没有接受完成,等待一段时间后,发送1xx多状态码
2. 2xx:成功。代表:200
3. 3xx:重定向。代表:302(重定向),304(访问缓存)
4. 4xx:客户端错误。
* 代表:
* 404(请求路径没有对应的资源)
* 405:请求方式没有对应的doXxx方法
5. 5xx:服务器端错误。代表:500(服务器内部出现异常)
2. 响应头:
1. 格式:头名称: 值
2. 常见的响应头:
1. Content-Type:服务器告诉客户端本次响应体数据格式以及编码格式
2. Content-disposition:服务器告诉客户端以什么格式打开响应体数据
* 值:
* in-line:默认值,在当前页面内打开
* attachment;filename=xxx:以附件形式打开响应体。文件下载
3. 响应空行
4. 响应体:传输的数据
* 响应字符串格式
响应行 HTTP/1.1 200 OK
响应头 Content-Type: text/html;charset=UTF-8
Content-Length: 101
Date: Wed, 06 Jun 2018 07:08:42 GMT
响应空行
响应体
$Title$
hello , response
5. request对象 & response对象
5.1 request和response的作用
1. request对象和response对象的原理
1. request和response对象是由服务器创建的。我们来使用它们
2. request对象是来获取请求消息,response对象是来设置响应消息
request对象和response对象的作用 |
5.2 request对象
5.2.1 request对象继承体系结构
2. request对象继承体系结构:
ServletRequest -- 接口
| 继承
HttpServletRequest -- 接口
| 实现
org.apache.catalina.connector.RequestFacade 类(tomcat实现)
5.2.2 request的功能——获取请求消息数据&其他功能
5.2.2.1 获取请求消息数据
3. request功能:
1. 获取请求消息数据
1. 获取请求行数据
假设请求行数据为:GET /day14/demo1?name=zhangsan HTTP/1.1
方法:
1. 获取请求方式 :GET
对应方法:String getMethod()
2. (*)获取虚拟目录:/day14
对应方法:String getContextPath()
3. 获取Servlet路径: /demo1
对应方法:String getServletPath()
4. 获取get方式请求参数:name=zhangsan
对应方法:String getQueryString()
5. (*)获取请求URI:/day14/demo1
对应方法:String getRequestURI(): /day14/demo1
对应方法:StringBuffer getRequestURL() :http://localhost/day14/demo1
URL和URI区别:URI的“范围”更大
URL:统一资源定位符 : http://localhost/day14/demo1 类比:中华人民共和国
URI:统一资源标识符 : /day14/demo1 类比:共和国
6. 获取协议及版本:HTTP/1.1
对应方法:String getProtocol()
7. 获取客户机的IP地址:
对应方法:String getRemoteAddr()
8.例程:获取请求行数据演示
package cn.itcast.web.request;
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;
/**
* 演示Request对象获取请求行数据*/
@WebServlet("/requestDemo1")
public class RequestDemo1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1. 获取请求方式 :GET
String method = request.getMethod();
System.out.println(method);
//2.(*)获取虚拟目录:/day14
String contextPath = request.getContextPath();
System.out.println(contextPath);
//3. 获取Servlet路径: /demo1
String servletPath = request.getServletPath();
System.out.println(servletPath);
//4. 获取get方式请求参数:name=zhangsan
String queryString = request.getQueryString();
System.out.println(queryString);
//5.(*)获取请求URI:/day14/demo1
String requestURI = request.getRequestURI();
StringBuffer requestURL = request.getRequestURL();
System.out.println(requestURI);
System.out.println(requestURL);
//6. 获取协议及版本:HTTP/1.1
String protocol = request.getProtocol();
System.out.println(protocol);
//7. 获取客户机的IP地址:
String remoteAddr = request.getRemoteAddr();
System.out.println(remoteAddr);
}
}
2. 获取请求头数据
1.方法:
(*)String getHeader(String name):通过请求头的名称获取请求头的值
Enumeration getHeaderNames():获取所有的请求头名称
2.例程一:演示获取请求头数据
package cn.itcast.web.request;
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.util.Enumeration;
@WebServlet("/requestDemo2")
public class RequestDemo2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//演示获取请求头数据
//1.获取所有请求头名称
Enumeration headerNames = request.getHeaderNames();
//2.遍历
while(headerNames.hasMoreElements()){
String name = headerNames.nextElement();
//根据名称获取请求头的值
String value = request.getHeader(name);
System.out.println(name+"---"+value);
}
}
}
3.例程二:演示获取请求头数据:user-agent
package cn.itcast.web.request;
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.util.Enumeration;
//演示获取请求头数据:user-agent
@WebServlet("/requestDemo3")
public class RequestDemo3 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//演示获取请求头数据:user-agent
String agent = request.getHeader("user-agent");
//判断agent的浏览器版本
if(agent.contains("Chrome")){
//谷歌
System.out.println("谷歌来了...");
}else if(agent.contains("Firefox")){
//火狐
System.out.println("火狐来了...");
}
}
}
4.例程三:演示获取请求头数据:referer——referer可判断请求从哪来
package cn.itcast.web.request;
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("/requestDemo4")
public class RequestDemo4 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//演示获取请求头数据:referer
String referer = request.getHeader("referer");
System.out.println(referer);//http://localhost/day14/login.html
//防盗链
if(referer != null ){
if(referer.contains("/day14")){
//正常访问
// System.out.println("播放电影....");
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("播放电影....");
}else{
//盗链
//System.out.println("想看电影吗?来优酷吧...");
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("想看电影吗?来优酷吧...");
}
}
}
}
3. 获取请求体数据:
请求体:只有POST请求方式,才有请求体,在请求体中封装了POST请求的请求参数
获取请求体步骤:先获取流对象,再从流对象中拿数据
1. 获取流对象(请求体被封装在流对象中),有两种流对象——字节流和字符流
BufferedReader getReader():获取字符输入流,只能操作字符数据
ServletInputStream getInputStream():获取字节输入流,可以操作所有类型数据 (在文件上传知识点后讲解)
2. 再从流对象中拿数据
3. 例程:
(1)regist.html表单如下:
< !DOCTYPE html >
注册页面
(2)RequestDemo5.java如下:
package cn.itcast.web.request;
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.BufferedReader;
import java.io.IOException;
@WebServlet("/requestDemo5")
public class RequestDemo5 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取请求消息体--请求参数
//1.获取字符流
BufferedReader br = request.getReader();
//2.读取数据
String line = null;
while((line = br.readLine()) != null){
System.out.println(line);
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
5.2.2.2 其他功能
1. 获取请求参数通用方式:不论get还是post请求方式都可以使用下列方法来获取请求参数
1. String getParameter(String name):根据参数名称获取参数值 username=zs&password=123
2. String[] getParameterValues(String name):根据参数名称获取参数值的数组(多用于复选框) hobby=xx&hobby=game
3. Enumeration getParameterNames():获取所有请求的参数名称
4. Map getParameterMap():获取所有参数的map集合
5.例程:
(1)regist2.html内容:
注册页面
(2)
package cn.itcast.web.request;
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.BufferedReader;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Map;
import java.util.Set;
@WebServlet("/requestDemo6")
public class RequestDemo6 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//post 获取请求参数
//根据参数名称获取参数值
String username = request.getParameter("username");
/* System.out.println("post");
System.out.println(username);*/
//根据参数名称获取参数值的数组
String[] hobbies = request.getParameterValues("hobby");
/*for (String hobby : hobbies) {
System.out.println(hobby);
}*/
//获取所有请求的参数名称
Enumeration parameterNames = request.getParameterNames();
/*while(parameterNames.hasMoreElements()){
String name = parameterNames.nextElement();
System.out.println(name);
String value = request.getParameter(name);
System.out.println(value);
System.out.println("----------------");
}*/
// 获取所有参数的map集合
Map parameterMap = request.getParameterMap();
//遍历
Set keyset = parameterMap.keySet();
for (String name : keyset) {
//获取键获取值
String[] values = parameterMap.get(name);
System.out.println(name);
for (String value : values) {
System.out.println(value);
}
System.out.println("-----------------");
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//get 获取请求参数
/*
//根据参数名称获取参数值
String username = request.getParameter("username");
System.out.println("get");
System.out.println(username);*/
this.doPost(request,response);
}
}
6.获取请求参数过程中的常见问题——中文乱码问题:
get方式:tomcat 8 已经将get方式乱码问题解决了
post方式:会乱码
解决:在获取参数前,设置request的编码request.setCharacterEncoding("utf-8");
解决:
package cn.itcast.web.request;
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.util.Enumeration;
import java.util.Map;
import java.util.Set;
@WebServlet("/requestDemo7")
public class RequestDemo7 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.设置流的编码
request.setCharacterEncoding("utf-8");
//获取请求参数username
String username = request.getParameter("username");
System.out.println(username);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
2. 请求转发:一种在服务器内部的资源跳转方式
1. 步骤:
1. 通过request对象获取请求转发器对象:RequestDispatcher getRequestDispatcher(String path)
2. 使用RequestDispatcher对象来进行转发:forward(ServletRequest request, ServletResponse response)
2. 特点(面试题):
1. 浏览器地址栏路径不发生变化
2. 只能转发到当前服务器内部资源中。
3. 转发是一次请求(只对服务器做一次请求)
请求转发 |
3. 共享数据:
域对象:一个有作用范围的对象,可以在范围内共享数据
request域:代表一次请求的范围,一般用于请求转发的多个资源中共享数据
方法:
1. void setAttribute(String name,Object obj):存储数据
2. Object getAttitude(String name):通过键获取值
3. void removeAttribute(String name):通过键移除键值对
4. 获取ServletContext:
ServletContext getServletContext()
5.例程:
(1)requestDemo8类
package cn.itcast.web.request;
import javax.servlet.RequestDispatcher;
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("/requestDemo8")
public class RequestDemo8 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("demo8888被访问了。。。");
//转发到demo9资源
/*
RequestDispatcher requestDispatcher = request.getRequestDispatcher("/requestDemo9");
requestDispatcher.forward(request,response);
*/
//存储数据到request域中
request.setAttribute("msg","hello");
request.getRequestDispatcher("/requestDemo9").forward(request,response);
//request.getRequestDispatcher("http://www.itcast.cn").forward(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
(2)requestDemo9类
package cn.itcast.web.request;
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("/requestDemo9")
public class RequestDemo9 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取数据
Object msg = request.getAttribute("msg");
System.out.println(msg);
System.out.println("demo9999被访问了。。。");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
4. 获取ServletContext:
ServletContext getServletContext()
代码:
package cn.itcast.web.request;
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("/requestDemo10")
public class RequestDemo10 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext servletContext = request.getServletContext();
System.out.println(servletContext);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
5.2.3 案例:用户登录
5.2.3.1 案例需求
用户登录案例需求:
1.编写login.html登录页面
username & password 两个输入框
2.使用Druid数据库连接池技术,操作mysql,day14数据库中user表
3.使用JdbcTemplate技术封装JDBC
4.登录成功跳转到SuccessServlet展示:登录成功!用户名,欢迎您
5.登录失败跳转到FailServlet展示:登录失败,用户名或密码错误
5.2.3.2 分析&开发步骤
登录案例目录结构
|
分析&开发步骤
1. 创建项目,导入html页面,配置文件,jar包
Title
2. 创建数据库环境
1. 创建USER表
CREATE DATABASE day14;
USE day14;
CREATE TABLE USER(
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(32) UNIQUE NOT NULL,
PASSWORD VARCHAR(32) NOT NULL
);
2. druid.properties文件内容:
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///day14
username=root
password=root
initialSize=5
maxActive=10
maxWait=3000
3. 创建包cn.itcast.domain,创建类User(User类对应USER表)
package cn.itcast.domain;
/**
* 用户的实体类
*/
public class User {
private int id;
private String username;
private String password;
private String gender;
public void setHehe(String gender){
this.gender = gender;
}
public String getHehe(){
return gender;
}
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;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", gender='" + gender + '\'' +
'}';
}
}
4. 创建包cn.itcast.util,编写工具类JDBCUtils
package cn.itcast.util;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import javax.xml.crypto.Data;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
/**
* JDBC工具类 使用Durid连接池
*/
public class JDBCUtils {
private static DataSource ds ;
static {
try {
//1.加载配置文件
Properties pro = new Properties();
//使用ClassLoader加载配置文件,获取字节输入流
InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties");
pro.load(is);
//2.初始化连接池对象
ds = DruidDataSourceFactory.createDataSource(pro);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取连接池对象
*/
public static DataSource getDataSource(){
return ds;
}
5. 创建包cn.itcast.dao,创建类UserDao,提供login方法
package cn.itcast.dao;
import cn.itcast.domain.User;
import cn.itcast.util.JDBCUtils;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
/**
* 操作数据库中User表的类
*/
public class UserDao {
//声明JDBCTemplate对象共用
private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
/**
* 登录方法
* @param loginUser 只有用户名和密码
* @return user包含用户全部数据,没有查询到,返回null
*/
public User login(User loginUser){
try {
//1.编写sql
String sql = "select * from user where username = ? and password = ?";
//2.调用query方法
User user = template.queryForObject(sql,
new BeanPropertyRowMapper(User.class),
loginUser.getUsername(), loginUser.getPassword());
return user;
} catch (DataAccessException e) {
e.printStackTrace();//记录日志
return null;
}
}
}
6. 编写cn.itcast.web.servlet.LoginServlet类
package cn.itcast.web.servlet;
import cn.itcast.dao.UserDao;
import cn.itcast.domain.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;
@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.设置编码
req.setCharacterEncoding("utf-8");
//2.获取请求参数
String username = req.getParameter("username");
String password = req.getParameter("password");
//3.封装user对象
User loginUser = new User();
loginUser.setUsername(username);
loginUser.setPassword(password);
//4.调用UserDao的login方法
UserDao dao = new UserDao();
User user = dao.login(loginUser);
//5.判断user
if(user == null){
//登录失败
req.getRequestDispatcher("/failServlet").forward(req,resp);
}else{
//登录成功
//存储数据
req.setAttribute("user",user);
//转发
req.getRequestDispatcher("/successServlet").forward(req,resp);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req,resp);
}
}
7. 编写FailServlet和SuccessServlet类
@WebServlet("/successServlet")
public class SuccessServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取request域中共享的user对象
User user = (User) request.getAttribute("user");
if(user != null){
//给页面写一句话
//设置编码
response.setContentType("text/html;charset=utf-8");
//输出
response.getWriter().write("登录成功!"+user.getUsername()+",欢迎您");
}
}
@WebServlet("/failServlet")
public class FailServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//给页面写一句话
//设置编码
response.setContentType("text/html;charset=utf-8");
//输出
response.getWriter().write("登录失败,用户名或密码错误");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
8.编写测试类UserDaoTest和BeanUtilsTest
1、类UserDaoTest
package cn.itcast.test;
import cn.itcast.dao.UserDao;
import cn.itcast.domain.User;
import org.junit.Test;
public class UserDaoTest {
@Test
public void testLogin(){
User loginuser = new User();
loginuser.setUsername("superbaby");
loginuser.setPassword("123111");
UserDao dao = new UserDao();
User user = dao.login(loginuser);
System.out.println(user);
}
}
2、BeanUtilsTest
//BeanUtils工具类中setProperty方法和getProperty方法演示:
package cn.itcast.test;
import cn.itcast.domain.User;
import org.apache.commons.beanutils.BeanUtils;
import org.junit.Test;
import java.lang.reflect.InvocationTargetException;
public class BeanUtilsTest {
@Test
public void test(){
User user = new User();
try {
BeanUtils.setProperty(user,"hehe","male");
System.out.println(user);
String gender = BeanUtils.getProperty(user, "hehe");
System.out.println(gender);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
9. 总结一: login.html中form表单的action路径的写法
* 虚拟目录+Servlet的资源路径
10. 总结二:BeanUtils工具类,简化数据封装(使用BeanUtils要导入jar包到WEB-INF下——commons-beanutils-1.8.0.jar)
* 用于封装JavaBean的
1. JavaBean:标准的Java类
1. 要求:
1. 类必须被public修饰
2. 必须提供空参的构造器
3. 成员变量必须使用private修饰
4. 提供公共setter和getter方法
2. 功能:封装数据
2. 概念:
成员变量:
属性:setter和getter方法截取后的产物
例如:getUsername() --> Username--> username
3. 方法:
1. setProperty():设置属性值
2. getProperty():获取属性值
3. populate(Object obj , Map map):将map集合的键值对信息,封装到对应的JavaBean对象中
4.BeanUtils的使用见上面BeanUtilsTest类、及下面代码(BeanUtils改写LoginServlet):
package cn.itcast.web.servlet;
import cn.itcast.dao.UserDao;
import cn.itcast.domain.User;
import org.apache.commons.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.lang.reflect.InvocationTargetException;
import java.util.Map;
@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.设置编码
req.setCharacterEncoding("utf-8");
//2.获取所有请求参数
Map map = req.getParameterMap();
//3.创建User对象
User loginUser = new User();
//3.2使用BeanUtils封装
try {
BeanUtils.populate(loginUser,map);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
//4.调用UserDao的login方法
UserDao dao = new UserDao();
User user = dao.login(loginUser);
//5.判断user
if(user == null){
//登录失败
req.getRequestDispatcher("/failServlet").forward(req,resp);
}else{
//登录成功
//存储数据
req.setAttribute("user",user);
//转发
req.getRequestDispatcher("/successServlet").forward(req,resp);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req,resp);
}
}
5.3 response对象
5.3.1 response对象功能——设置响应消息
* 功能:设置响应消息
1. 设置响应行
1. 格式:HTTP/1.1 200 ok
2. 设置状态码:setStatus(int sc)
2. 设置响应头:setHeader(String name, String value)
3. 设置响应体:
* 使用步骤:
1. 获取输出流
* 字符输出流:PrintWriter getWriter()
* 字节输出流:ServletOutputStream getOutputStream()
2. 使用输出流,将数据输出到客户端浏览器
5.3.2 案例一:完成重定向 & 服务器输出字符数据到浏览器 & 服务器输出字节数据到浏览器
1. 完成重定向
重定向示意图 |
* 案例:
1. 完成重定向
1、重定向:资源跳转的方式
2、代码实现:
//1. 设置状态码为302
response.setStatus(302);
//2.设置响应头location
response.setHeader("location","/day15/responseDemo2");
//简单的重定向方法
response.sendRedirect("/day15/responseDemo2");
3、forward和redirect区别:
重定向的特点:redirect
1. 地址栏发生变化
2. 重定向可以访问其他站点(服务器)的资源
3. 重定向是两次请求。不能使用request对象来共享数据
转发的特点:forward
1. 转发地址栏路径不变
2. 转发只能访问当前服务器下的资源
3. 转发是一次请求,可以使用request对象来共享数据
4、重定向例程: 访问 /responseDemo1,自动跳转到/responseDemo2资源
1.responseDemo1类:
package cn.itcast.web.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;
/**
* 重定向
* 访问 /responseDemo1,会自动跳转到/responseDemo2资源
*/
@WebServlet("/responseDemo1")
public class ResponseDemo1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("demo1被访问了........");
/* //1. 设置状态码为302
response.setStatus(302);
//2.设置响应头location
response.setHeader("location","/day15/responseDemo2");*/
request.setAttribute("msg","response");
//动态获取虚拟目录
String contextPath = request.getContextPath();
//简单的重定向方法
response.sendRedirect(contextPath+"/responseDemo2");
//response.sendRedirect("http://www.itcast.cn");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
2.responseDemo2类
package cn.itcast.web.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;
@WebServlet("/responseDemo2")
public class ResponseDemo2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("demo2被访问了........");
Object msg = request.getAttribute("msg");
System.out.println(msg);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
3.控制台输出:
demo1被访问了........
demo2被访问了........
null
2. 服务器输出字符数据到浏览器
2. 服务器输出字符数据到浏览器
1. 步骤:
1. 获取字符输出流
2. 输出数据
2.注意:
* 乱码问题:
1. PrintWriter pw = response.getWriter();获取的流的默认编码是ISO-8859-1
2. 设置该流的默认编码
3. 告诉浏览器响应体使用的编码
//简单的形式,设置编码,是在获取流之前设置
response.setContentType("text/html;charset=utf-8");
3.例程:
package cn.itcast.web.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("/responseDemo4")
public class ResponseDemo4 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取流对象之前,设置流的默认编码:ISO-8859-1 设置为:GBK
// response.setCharacterEncoding("utf-8");
//告诉浏览器,服务器发送的消息体数据的编码。建议浏览器使用该编码解码
//response.setHeader("content-type","text/html;charset=utf-8");
//简单的形式,设置编码
response.setContentType("text/html;charset=utf-8");
//1.获取字符输出流
PrintWriter pw = response.getWriter();
//2.输出数据
//pw.write("hello response
");
pw.write("你好啊啊啊 response");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
3. 服务器输出字节数据到浏览器
3. 服务器输出字节数据到浏览器
1.步骤:
1. 获取字节输出流
2. 输出数据
2.例程:
package cn.itcast.web.servlet;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
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("/responseDemo5")
public class ResponseDemo5 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
//1.获取字节输出流
ServletOutputStream sos = response.getOutputStream();
//2.输出数据
sos.write("你好".getBytes("utf-8"));
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
4. 资源路径写法
路径写法:
1. 路径分类
1. 相对路径:通过相对路径不可以确定唯一资源
* 如:./index.html
* 不以/开头,以.开头路径
* 规则:找到当前资源和目标资源之间的相对位置关系
* ./:当前目录(./可以省略不写——不写代表./)
* ../:后退一级目录
例子一:
若当前资源为:location.html
http://localhost/day15/location.html
若目标资源为:
http://localhost/day15/responseDemo2
则相对路径为: ./responseDemo2 或 responseDemo2
绝对路径为: /day15/responseDemo2
例子二:
若当前资源为:location.html
http://localhost/day15/htmls/location2.html
若目标资源为:
http://localhost/day15/responseDemo2
则相对路径为:../responseDemo2
2. 绝对路径:通过绝对路径可以确定唯一资源
如:http://localhost/day15/responseDemo2 /day15/responseDemo2
简单理解为以/开头的路径
规则:判断定义的路径是给谁用的?判断请求将来从哪儿发出
给客户端浏览器使用:需要加虚拟目录(项目的访问路径)
建议虚拟目录动态获取:request.getContextPath()
例如: 、
5. 实现验证码
4. 验证码
1. 本质:图片
2. 目的:防止恶意表单注册
3. 例程:
package cn.itcast.web.servlet;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
@WebServlet("/checkCodeServlet")
public class CheckCodeServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int width = 100;
int height = 50;
//1.创建一对象,在内存中图片(验证码图片对象)
BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
//2.美化图片
//2.1 填充背景色
Graphics g = image.getGraphics();//画笔对象
g.setColor(Color.PINK);//设置画笔颜色
g.fillRect(0,0,width,height);
//2.2画边框
g.setColor(Color.BLUE);
g.drawRect(0,0,width - 1,height - 1);
String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghigklmnopqrstuvwxyz0123456789";
//生成随机角标
Random ran = new Random();
for (int i = 1; i <= 4; i++) {
int index = ran.nextInt(str.length());
//获取字符
char ch = str.charAt(index);//随机字符
//2.3写验证码
g.drawString(ch+"",width/5*i,height/2);
}
//2.4画干扰线
g.setColor(Color.GREEN);
//随机生成坐标点
for (int i = 0; i < 10; i++) {
int x1 = ran.nextInt(width);
int x2 = ran.nextInt(width);
int y1 = ran.nextInt(height);
int y2 = ran.nextInt(height);
g.drawLine(x1,y1,x2,y2);
}
//3.将图片输出到页面展示
ImageIO.write(image,"jpg",response.getOutputStream());
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
4.验证码切换:点击图片实现验证码切换
视频地址:https://www.bilibili.com/video/BV1qv4y1o79t?p=275&vd_source=60482f480b98c4a8ef39f39be38a8b56
Title
看不清换一张?
验证码效果如下:
6. ServletContext对象:
6.1 概念 & 获取ServletContext对象
1. 概念:代表整个web应用,可以和程序的容器(服务器)进行通信
2. 如何获取ServletContext对象:
1. 通过request对象获取ServletContext对象
request.getServletContext();
2. 通过HttpServlet获取ServletContext对象
this.getServletContext();
3.注:两种方式获取的ServletContext对象是同一个
package cn.itcast.web.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("/servletContextDemo1")
public class ServletContextDemo1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*
ServletContext对象获取:
1. 通过request对象获取
request.getServletContext();
2. 通过HttpServlet获取
this.getServletContext();
*/
//1. 通过request对象获取
ServletContext context1 = request.getServletContext();
//2. 通过HttpServlet获取
ServletContext context2 = this.getServletContext();
System.out.println(context1);
System.out.println(context2);
System.out.println(context1 == context2);//true
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
6.2 ServletContext对象的功能
3. 功能:
1. 获取MIME类型(互联网中文件的一种类型):
1.MIME类型:在互联网通信过程中定义的一种文件数据类型
格式: 大类型/小类型 如:text/html image/jpeg
2.获取:String getMimeType(String file)
3.例程:
package cn.itcast.web.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("/servletContextDemo2")
public class ServletContextDemo2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1. 通过HttpServlet获取
ServletContext context = this.getServletContext();
//2. 定义文件名称
String filename = "a.jpg";//image/jpeg
//3.获取MIME类型
String mimeType = context.getMimeType(filename);
System.out.println(mimeType);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
2. ServletContext是一个域对象,可以共享数据
1. setAttribute(String name,Object value)
2. getAttribute(String name)
3. removeAttribute(String name)
ServletContext对象范围:所有用户所有请求的数据
注: ServletContext对象共享所有数据且生命周期很长,因此要谨慎使用
例一:
package cn.itcast.web.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("/servletContextDemo3")
public class ServletContextDemo3 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*
ServletContext功能:
1. 获取MIME类型:
2. 域对象:共享数据
3. 获取文件的真实(服务器)路径 */
//2. 通过HttpServlet获取
ServletContext context = this.getServletContext();
//设置数据
context.setAttribute("msg","haha");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
例二:
package cn.itcast.web.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("/servletContextDemo4")
public class ServletContextDemo4 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//2. 通过HttpServlet获取
ServletContext context = this.getServletContext();
//获取数据
Object msg = context.getAttribute("msg");
System.out.println(msg);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
3. 获取文件的真实(服务器)路径
1. 方法:String getRealPath(String path)
String b = context.getRealPath("/b.txt");//web目录下资源访问
System.out.println(b);
String c = context.getRealPath("/WEB-INF/c.txt");//WEB-INF目录下的资源访问
System.out.println(c);
String a = context.getRealPath("/WEB-INF/classes/a.txt");//src目录下的资源访问
System.out.println(a);
6.3 案例
文件下载需求:
1. 页面显示超链接
2. 点击超链接后弹出下载提示框
3. 完成图片文件下载
分析:
1. 超链接指向的资源如果能够被浏览器解析(如图片通常可以被解析),则在浏览器中展示,如果不能解析(如视频通常不能被解析),则弹出下载提示框。不满足需求
2. 任何资源都必须弹出下载提示框
3. 使用响应头设置资源的打开方式:
content-disposition:attachment;filename=xxx
目录结构
目录结构 |
实现步骤:
1. 定义页面,编辑超链接href属性,指向Servlet,传递资源名称filename
Title
图片1
视频
图片1
视频
2. 定义Servlet
1. 获取文件名称
2. 使用字节输入流加载文件进内存
3. 指定response的响应头: content-disposition:attachment;filename=xxx
4. 将数据写出到response输出流
5.完整代码:
package cn.itcast.web.download;
import cn.itcast.web.utils.DownLoadUtils;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
@WebServlet("/downloadServlet")
public class DownloadServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.获取请求参数,文件名称
String filename = request.getParameter("filename");
//2.使用字节输入流加载文件进内存
//2.1找到文件服务器路径
ServletContext servletContext = this.getServletContext();
String realPath = servletContext.getRealPath("/img/" + filename);
//2.2用字节流关联
FileInputStream fis = new FileInputStream(realPath);
//3.设置response的响应头
//3.1设置响应头类型:content-type
String mimeType = servletContext.getMimeType(filename);//获取文件的mime类型
response.setHeader("content-type",mimeType);
//3.2设置响应头打开方式:content-disposition
//解决中文文件名问题
//1.获取user-agent请求头、
String agent = request.getHeader("user-agent");
//2.使用工具类方法编码文件名即可
filename = DownLoadUtils.getFileName(agent, filename);
response.setHeader("content-disposition","attachment;filename="+filename);
//4.将输入流的数据写出到输出流中
ServletOutputStream sos = response.getOutputStream();
byte[] buff = new byte[1024 * 8];
int len = 0;
while((len = fis.read(buff)) != -1){
sos.write(buff,0,len);
}
fis.close();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
问题:中文文件名显示异常
问题:
中文文件名显示异常问题
解决思路:
1. 获取客户端使用的浏览器版本信息
2. 根据不同的版本信息,设置filename的编码方式不同
3. 上面DownloadServlet 类中已经通过调用如下DownLoadUtils类的方法解决了乱码问题:
package cn.itcast.web.utils;
import sun.misc.BASE64Encoder;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
public class DownLoadUtils {
public static String getFileName(String agent, String filename) throws UnsupportedEncodingException {
if (agent.contains("MSIE")) {
// IE浏览器
filename = URLEncoder.encode(filename, "utf-8");
filename = filename.replace("+", " ");
} else if (agent.contains("Firefox")) {
// 火狐浏览器
BASE64Encoder base64Encoder = new BASE64Encoder();
filename = "=?utf-8?B?" + base64Encoder.encode(filename.getBytes("utf-8")) + "?=";
} else {
// 其它浏览器
filename = URLEncoder.encode(filename, "utf-8");
}
return filename;
}
}
7. 会话技术——Cookie & Session
1. 会话:一次会话中包含多次请求和响应。
一次会话:浏览器第一次给服务器资源发送请求,会话建立,直到有一方断开为止
2. 功能:在一次会话的范围内的多次请求间,共享数据
3. 方式:
1. 客户端会话技术:Cookie
2. 服务器端会话技术:Session
7.1 Cookie
7.1.1 Cookie的概念 & 代码入门
1. 概念:客户端会话技术,将数据保存到客户端
2. 快速入门:
使用步骤:
1. 创建Cookie对象,绑定数据
new Cookie(String name, String value)
2. 发送Cookie对象
response.addCookie(Cookie cookie)
3. 获取Cookie,拿到数据
Cookie[] request.getCookies()
4.示例代码:
1.cookieDemo1类——发送Cookie对象
package cn.itcast.cookie;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Cookie快速入门
*/
@WebServlet("/cookieDemo1")
public class CookieDemo1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.创建Cookie对象
Cookie c = new Cookie("msg","hello");
//2.发送Cookie
response.addCookie(c);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
2.cookieDemo2类——获取Cookie,拿到数据
package cn.itcast.cookie;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Cookie快速入门*/
@WebServlet("/cookieDemo2")
public class CookieDemo2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//3. 获取Cookie
Cookie[] cs = request.getCookies();
//获取数据,遍历Cookies
if(cs != null){
for (Cookie c : cs) {
String name = c.getName();
String value = c.getValue();
System.out.println(name+":"+value);
}
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
7.1.2 cookie实现原理
3. 实现原理
基于响应头set-cookie和请求头cookie实现
原理:CookieDemo1将信息封装到响应头set-cookie中发送给客户端,客户端再将Cookie信息放在请求头中发送到服务器端,CookieDemo2可以通过具体方法获取信息 |
7.1.3 cookie的细节
4. cookie的细节
1. 一次可不可以发送多个cookie?
可以
可以创建多个Cookie对象,使用response调用多次addCookie方法发送cookie即可。
示例代码:
package cn.itcast.cookie;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
*Cookie快速入门*/
@WebServlet("/cookieDemo3")
public class CookieDemo3 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.创建Cookie对象
Cookie c1 = new Cookie("msg","hello");
Cookie c2 = new Cookie("name","zhangsan");
//2.发送Cookie
response.addCookie(c1);
response.addCookie(c2);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
2. cookie在浏览器中保存多长时间?
1. 默认情况下,当浏览器关闭后,Cookie数据被销毁
2. 持久化存储:
setMaxAge(int seconds)
1. 正数:将Cookie数据写到硬盘的文件中。持久化存储。并指定cookie存活时间,时间到后,cookie文件自动失效
2. 负数:默认值——当浏览器关闭后,Cookie数据被销毁
3. 零:删除cookie信息
4. 示例代码:
package cn.itcast.cookie;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**Cookie快速入门*/
@WebServlet("/cookieDemo4")
public class CookieDemo4 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.创建Cookie对象
Cookie c1 = new Cookie("msg","setMaxAge");
//2.设置cookie的存活时间
//c1.setMaxAge(30);//将cookie持久化到硬盘,30秒后会自动删除cookie文件
//c1.setMaxAge(-1);
//c1.setMaxAge(300);
c1.setMaxAge(0);//删除Cookie
//3.发送Cookie
response.addCookie(c1);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
3. cookie能不能存中文?
在tomcat 8 之前 cookie中不能直接存储中文数据。
需要将中文数据转码---一般采用URL编码(%E3)
在tomcat 8(包含8)之后,cookie支持中文数据。特殊字符还是不支持,建议使用URL编码存储,URL解码解析
Cookie c1 = new Cookie("msg","你好");
response.addCookie(c1);
4. cookie共享问题?——cookie的获取范围有多大
1. 假设在一个tomcat服务器中,部署了多个web项目,那么在这些web项目中cookie能不能共享?
默认情况下cookie不能共享
setPath(String path):设置cookie的获取范围。默认情况下,设置当前的虚拟目录
如果要使当前服务器下都共享到,则可以将path设置为"/"
例程:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.创建Cookie对象
Cookie c1 = new Cookie("msg","你好");
//设置path,让当前服务器下部署的所有项目共享Cookie信息
c1.setPath("/");
//c1.setPath("/day16"); —— /day16下的项目都可以获取
//3.发送Cookie
response.addCookie(c1);
}
2. 不同的tomcat服务器间cookie共享问题?
setDomain(String path):如果设置一级域名相同,那么多个服务器之间cookie可以共享
setDomain(".baidu.com"),那么tieba.baidu.com和news.baidu.com中cookie可以共享
7.1.3 Cookie的特点和作用
5. Cookie的特点和作用
1. cookie存储数据在客户端浏览器,存在于客户端的数据容易丢失,容易被篡改,不安全
2. 浏览器对于单个cookie 的大小有限制(4kb) 以及 对同一个域名下的总cookie数量也有限制(20个)
作用:
1. cookie一般用于存出少量的不太敏感的数据
2. 在不登录的情况下,完成服务器对客户端的身份识别
7.1.4 案例:记住上一次访问时间
6. 案例:记住上一次访问时间
1. 需求:
1. 访问一个Servlet,如果是第一次访问,则提示:您好,欢迎您首次访问。
2. 如果不是第一次访问,则提示:欢迎回来,您上次访问时间为:显示时间字符串
2. 分析:
1. 可以采用Cookie来完成
2. 在服务器中的Servlet判断是否有一个名为lastTime的cookie
1. 有:不是第一次访问
1. 响应数据:欢迎回来,您上次访问时间为:2018年6月10日11:50:20
2. 写回Cookie:lastTime=2018年6月10日11:50:01
2. 没有:是第一次访问
1. 响应数据:您好,欢迎您首次访问
2. 写回Cookie:lastTime=2018年6月10日11:50:01
案例分析 |
3. 代码实现:
package cn.itcast.cookie;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
@WebServlet("/cookieTest")
public class CookieTest extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置响应的消息体的数据格式以及编码
response.setContentType("text/html;charset=utf-8");
//1.获取所有Cookie
Cookie[] cookies = request.getCookies();
boolean flag = false;//没有cookie为lastTime
//2.遍历cookie数组
if(cookies != null && cookies.length > 0){
for (Cookie cookie : cookies) {
//3.获取cookie的名称
String name = cookie.getName();
//4.判断名称是否是:lastTime
if("lastTime".equals(name)){
//有该Cookie,不是第一次访问
flag = true;//有lastTime的cookie
//设置Cookie的value
//获取当前时间的字符串,重新设置Cookie的值,重新发送cookie
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String str_date = sdf.format(date);
System.out.println("编码前:"+str_date);
//URL编码
str_date = URLEncoder.encode(str_date,"utf-8");
System.out.println("编码后:"+str_date);
cookie.setValue(str_date);
//设置cookie的存活时间
cookie.setMaxAge(60 * 60 * 24 * 30);//一个月
response.addCookie(cookie);
//响应数据
//获取Cookie的value,时间
String value = cookie.getValue();
System.out.println("解码前:"+value);
//URL解码:
value = URLDecoder.decode(value,"utf-8");
System.out.println("解码后:"+value);
response.getWriter().write("欢迎回来,您上次访问时间为:"+value+"
");
break;
}
}
}
if(cookies == null || cookies.length == 0 || flag == false){
//没有,第一次访问
//设置Cookie的value
//获取当前时间的字符串,重新设置Cookie的值,重新发送cookie
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String str_date = sdf.format(date);
System.out.println("编码前:"+str_date);
//URL编码
str_date = URLEncoder.encode(str_date,"utf-8");
System.out.println("编码后:"+str_date);
Cookie cookie = new Cookie("lastTime",str_date);
//设置cookie的存活时间
cookie.setMaxAge(60 * 60 * 24 * 30);//一个月
response.addCookie(cookie);
response.getWriter().write("您好,欢迎您首次访问
");
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
7.2 JSP 入门学习
1. 概念:
Java Server Pages: java服务器端页面
可以理解为:一个特殊的页面,其中既可以指定定义html标签,又可以定义java代码
用于简化书写!!!
2. 原理
JSP本质上就是一个Servlet
原理:JSP本质上就是一个Servlet , jsp文件转换后会生成一个Java文件 , 编译后生成一个class文件 ,可在对应的目录下查看 |
3. JSP的脚本:JSP定义Java代码的方式
1. <% 代码 %>:定义的java代码,在service方法中。service方法中可以定义什么,该脚本中就可以定义什么。
2. <%! 代码 %>:定义的java代码,在jsp转换后的java类的成员位置。
3. <%= 代码 %>:定义的java代码,会输出到页面上。输出语句中可以定义什么,该脚本中就可以定义什么。
4. JSP的内置对象:
内置对象:在jsp页面中不需要获取和创建,可以直接使用的对象
jsp一共有9个内置对象。
今天学习3个:
1.request对象
2.response对象
3.out对象:字符输出流对象。可以将数据输出到页面上。和response.getWriter()类似
response.getWriter()和out.write()的区别:
1.在tomcat服务器真正给客户端做出响应之前,会先找response缓冲区数据,再找out缓冲区数据。
2.response.getWriter()数据输出永远在out.write()之前
5. 案例:改造Cookie案例
7.3 Session
7.3.1 Session概念 & 快速入门
1. Session(主菜)概念:服务器端会话技术,在一次会话的多次请求间共享数据,将数据保存在服务器端的对象中。HttpSession
2. 快速入门:
1. 获取HttpSession对象:
HttpSession session = request.getSession();
2. 使用HttpSession对象:
Object getAttribute(String name)
void setAttribute(String name, Object value)
void removeAttribute(String name)
3.例程:
1.sessionDemo1类
@WebServlet("/sessionDemo1")
public class SessionDemo1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//使用session共享数据
//1.获取session
HttpSession session = request.getSession();
//2.存储数据
session.setAttribute("msg","hello session");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
2.sessionDemo2类
@WebServlet("/sessionDemo2")
public class SessionDemo2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//使用session获取数据
//1.获取session
HttpSession session = request.getSession();
//2.获取数据
Object msg = session.getAttribute("msg");
System.out.println(msg);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
7.3.2 Session原理
3. 原理
Session的实现是依赖于Cookie的。
7.3.3 Session的细节
4. Session的细节:
1. 当客户端关闭后,服务器不关闭,两次获取session是否为同一个?
默认情况下,不是。
如果需要相同,则可以创建Cookie,键为JSESSIONID,设置最大存活时间,让cookie持久化保存。
@WebServlet("/sessionDemo3")
public class SessionDemo3 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.获取session
HttpSession session = request.getSession();
System.out.println(session);
//期望客户端关闭后,session也能相同
Cookie c = new Cookie("JSESSIONID",session.getId());
c.setMaxAge(60*60);
response.addCookie(c);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
2. 客户端不关闭,服务器关闭后,两次获取的session是同一个吗?
不是同一个,但是要确保数据不丢失。tomcat自动完成以下工作
session的钝化:
在服务器正常关闭之前,将session对象系列化到硬盘上
session的活化:
在服务器启动后,将session文件转化为内存中的session对象即可。
https://www.bilibili.com/video/BV1qv4y1o79t?p=303&spm_id_from=pageDriver&vd_source=60482f480b98c4a8ef39f39be38a8b56
3. session的实效时间?————session什么时候被销毁?
1. 服务器关闭
2. session对象调用invalidate() 销毁自己
3. session默认失效时间 30分钟
4.选择性配置修改————设置session的失效时间(单位:分钟):配置文件目录位置apache-tomcat-8.5.81\conf\web.xml
30
7.3.4 session的特点
5. session的特点
1. session用于存储一次会话的多次请求的数据,存在服务器端
2. session可以存储任意类型,任意大小的数据
session与Cookie的区别:
1. session存储数据在服务器端,Cookie在客户端
2. session没有数据大小限制,Cookie有
3. session数据安全,Cookie相对于不安全
7.3.5 案例:验证码
1. 案例需求:
1. 访问带有验证码的登录页面login.jsp
2. 用户输入用户名,密码以及验证码。
如果用户名和密码输入有误,跳转登录页面,提示:用户名或密码错误
如果验证码输入有误,跳转登录页面,提示:验证码错误
如果全部输入正确,则跳转到主页success.jsp,显示:用户名,欢迎您
2. 分析:
3.代码:
1.登录页面login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
login
<%=request.getAttribute("cc_error") == null ? "" : request.getAttribute("cc_error")%>
<%=request.getAttribute("login_error") == null ? "" : request.getAttribute("login_error") %>
2.checkCodeServlet类
@WebServlet("/checkCodeServlet")
public class CheckCodeServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int width = 100;
int height = 50;
//1.创建一对象,在内存中图片(验证码图片对象)
BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
//2.美化图片
//2.1 填充背景色
Graphics g = image.getGraphics();//画笔对象
g.setColor(Color.PINK);//设置画笔颜色
g.fillRect(0,0,width,height);
//2.2画边框
g.setColor(Color.BLUE);
g.drawRect(0,0,width - 1,height - 1);
String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghigklmnopqrstuvwxyz0123456789";
//生成随机角标
Random ran = new Random();
StringBuilder sb = new StringBuilder();
for (int i = 1; i <= 4; i++) {
int index = ran.nextInt(str.length());
//获取字符
char ch = str.charAt(index);//随机字符
sb.append(ch);
//2.3写验证码
g.drawString(ch+"",width/5*i,height/2);
}
String checkCode_session = sb.toString();
//将验证码存入session
request.getSession().setAttribute("checkCode_session",checkCode_session);
//2.4画干扰线
g.setColor(Color.GREEN);
//随机生成坐标点
for (int i = 0; i < 10; i++) {
int x1 = ran.nextInt(width);
int x2 = ran.nextInt(width);
int y1 = ran.nextInt(height);
int y2 = ran.nextInt(height);
g.drawLine(x1,y1,x2,y2);
}
//3.将图片输出到页面展示
ImageIO.write(image,"jpg",response.getOutputStream());
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
3.loginServlet类
@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.设置request编码
request.setCharacterEncoding("utf-8");
//2.获取参数
String username = request.getParameter("username");
String password = request.getParameter("password");
String checkCode = request.getParameter("checkCode");
//3.先获取生成的验证码
HttpSession session = request.getSession();
String checkCode_session = (String) session.getAttribute("checkCode_session");
//删除session中存储的验证码
session.removeAttribute("checkCode_session");
//3.先判断验证码是否正确
if(checkCode_session!= null && checkCode_session.equalsIgnoreCase(checkCode)){
//忽略大小写比较
//验证码正确
//判断用户名和密码是否一致
if("zhangsan".equals(username) && "123".equals(password)){//需要调用UserDao查询数据库
//登录成功
//存储信息,用户信息
session.setAttribute("user",username);
//重定向到success.jsp
response.sendRedirect(request.getContextPath()+"/success.jsp");
}else{
//登录失败
//存储提示信息到request
request.setAttribute("login_error","用户名或密码错误");
//转发到登录页面
request.getRequestDispatcher("/login.jsp").forward(request,response);
}
}else{
//验证码不一致
//存储提示信息到request
request.setAttribute("cc_error","验证码错误");
//转发到登录页面
request.getRequestDispatcher("/login.jsp").forward(request,response);
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
8. JSP
8.1 JSP作用 & JSP指令
1.JSP指令
1、JSP作用:用于配置JSP页面,导入资源文件
2、格式:
<%@ 指令名称 属性名1=属性值1 属性名2=属性值2 ... %>
如:<%@ page contentType="text/html;charset=UTF-8" language="java" %>
8.2 JSP 指令分类
3、指令分类————包含三类:page指令 、include指令 、taglib指令
8.2.1 page指令
1. page指令 : 配置JSP页面的
1.contentType:等同于response.setContentType()方法
1. 设置响应体的mime类型以及字符集
2. 设置当前jsp页面的编码(只能是高级的IDE才能生效,如果使用低级工具,则需要设置pageEncoding属性设置当前页面的字符集)
2.import:导包
3.errorPage:当前页面发生异常后,会自动跳转到指定的错误页面
4.isErrorPage:标识当前也是是否是错误页面。
1.true:是,可以使用内置对象exception
2.false:否。默认值。不可以使用内置对象exception
5.例程一:
<%@ page import="java.util.ArrayList" %>
<%@ page import="java.util.List" %>
<%@ page contentType="text/html;charset=gbk" errorPage="500.jsp" pageEncoding="GBK" language="java" buffer="16kb" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
$Title$
<%
List list = new ArrayList();
int i = 3/0;
%>
6.例程二:
<%@ page contentType="text/html;charset=UTF-8" isErrorPage="true" language="java" %>
Title
服务器正忙...
<%
String message = exception.getMessage();
out.print(message);
%>
8.2.2 include指令
2. include指令: 页面包含的。导入页面的资源文件
例程:
1.文件top.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
页面logo页面标题
2.文件home.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@include file="top.jsp"%>
Title
主体信息
程序效果
8.2.3 taglib指令
3. taglib指令 : 导入资源
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
prefix:前缀,自定义的
8.2.4 jsp注释 & jsp内置对象
2. 注释:
1. html注释:
:只能注释html代码片段
2. jsp特有注释:推荐使用
<%-- --%>:可以注释所有
3. 内置对象
1.在jsp页面中不需要创建,直接使用的对象
2.一共有9个内置对象
3.下表前四个是域对象(pageContext、request、session、application),域对象是用来共享数据的
变量名 真实类型 作用
pageContext PageContext 当前页面共享数据,还可以获取其他八个内置对象
request HttpServletRequest 一次请求访问的多个资源(转发)
session HttpSession 一次会话的多个请求间
application ServletContext 所有用户间共享数据(只有一个对象,服务器开启时创建,关闭时销毁)
response HttpServletResponse 响应对象
page Object 当前页面(Servlet)的对象 this
out JspWriter 输出对象,数据输出到页面上
config ServletConfig Servlet的配置对象
exception Throwable 异常对象(只有在isErrorPage="true"的页面才可以使用)
4.使用方法:
1.pageContext只能在当前页面使用
<%
pageContext.setAttribute("msg","hello");
%>
<%=pageContext.getAttribute("msg")%>
说明:本内容整理自B站黑马程序员Java web课程视频及文档>>B站黑马程序员Java web课程视频