一、引言
1.1 C/S架构和B/S架构
C/S和B/S是软件发展过程中出现的两种软件架构方式。
1.2 C/S架构(Client/Server 客户端/服务器)
- 特点:必须在客户端安装特定软件
- 优点:图形效果显示较好(如:3D游戏)
- 缺点:服务器的软件和功能进行升级,客户端也必须升级、不利于维护
- 常见的C/S程序:QQ、微信等
1.3 B/S架构(Browser/Server 浏览器/服务器)
- 特点:无需安装客户端,任何浏览器都可直接访问
- 优点:涉及到功能的升级,只需要升级服务器端
- 缺点:图形显示效果不如C/S架构
- 需要通过HTTP协议访问
二 、服务器
2.1 概念
服务器分为两大类:一类是硬件服务器,就是一台比普通计算机更强的主机服务器;一类就是软件服务器,就是一个软件,安装在硬件电脑中
2.1.1 javaee规范概述
java 2 platomform enterprise : java企业版
在1.0到1.4时,称为j2ee,从5.0开始,称为javaee
进行服务器技术开发的技术规范,总共有13个:jsp/servlet、jdbc、jndi、jni等等
2.1.2 什么是Web
- Web(World Wide Web) 称为万维网,简单理解就是网站,它用来表示Internet主机上供外界访问的资源。html、css、js属于万维网技术。web只要作用是想让本地电脑中的资源能够实现共享,别人的电脑通过输入网址的形式来访问该资源
- Internet上供外界访问的资源分为两大类
-
静态资源:指Web页面中供人们浏览的数据始终是不变的。(HTML、CSS)
-
动态资源:指Web页面中供人们浏览的数据是由程序产生的,不同时间点,甚至不同设备访问Web页面看到的内容各不相同。(JSP/Servlet)
-
在Java中,动态Web资源开发技术我们统称为Java Web。
-
2.1.2 什么是Web服务器
-
Web服务器是运行及发布Web应用的容器,只有将开发的Web项目放置到该容器中,才能使网络中的所有用户通过浏览器进行访问。
-
服务器的简单作用:共享资源,任何人都可以通过浏览器进行访问
2.2 常见服务器
什么是服务器?
1.就是一台电脑(大型计算机)
2.是在电脑中安装一个服务器软件
- 开源:OpenSource(1、开放源代码 2、免费)
- Tomcat(主流Web服务器之一,适合初学者)
- jetty(淘宝,运行效率比Tomcat高)
- resin(新浪,所有开源服务器软件中,运行效率最高的)
- 三者的用法从代码角度完全相同,只有在开启、关闭服务器软件时对应的命令稍有区别。掌握一个即掌握所有
- 收费
- WebLogic(Oracle)
- WebSphere(IBM)
- 提供相应的服务与支持,软件大,耗资源
2.3 Tomcat服务器
-
Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,免费开源、并支持Servlet 和JSP 规范。目前Tomcat最新版本为10.0。
-
Tomcat 技术先进、性能稳定,深受Java 爱好者喜爱并得到了部分软件开发商的认可,成为目前比较流行的Web 应用服务器。本身其实就是一个服务器软件
2.4 Tomcat安装
2.4.1 下载
- 官网下载(tomcat下载)
2.4.2 解压安装
- 将Tomcat解压到一个没有特殊符号的目录中(一般纯英文即可)
- 注意
- 不建议将服务器软件放在磁盘层次很多的文件夹
- 不建议放在中文路径下
2.4.3 Tomcat目录结构
文件夹 | 说明 | 备注 |
---|---|---|
bin | 该目录下存放的是二进制可执行文件 | startup.bat启动Tomcat、shutdown.bat停止Tomcat |
conf | 该目录下存放的是一些配置文件,这是一个非常重要的目录,这个目录下有两个最为重要的文件server.xml和web.xml | server.xml:配置整个服务器信息。例如修改端口号,编码格式等。 web.xml:项目部署描述符文件,这个文件中注册了很多MIME类型,即文档类型。 |
lib | Tomcat的类库,里面存放Tomcat运行所需要的jar文件。 | |
logs | 存放日志文件,记录了Tomcat启动和关闭的信息,如果启动Tomcat时有错误,异常也会记录在日志文件中。 | |
temp | Tomcat的临时文件,这个目录下的东西在停止Tomcat后删除。 | |
webapps | 存放web项目的目录,其中每个文件夹都是一个项目;其中ROOT是一个特殊的项目,在地址栏中没有给出项目目录时,对应的就是ROOT项目。 | |
work | 运行时生成的文件,最终运行的文件都在这里。 | 当客户端用户访问一个JSP文件时,Tomcat会通过JSP生成Java文件,然后再编译Java文件生成class文件,生成的java和class文件都会存放到这个目录下。 |
- 修改tomcat端口号
Tomcat默认端口号为8080,可以通过conf/server.xml文件修改
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
注意:修改端口号需要重新启动Tomcat才能生效
2.6 项目部署及访问静态资源
- Tomcat是Web服务器,我们的项目应用是部署在webapps下,然后通过特定的URL访问。
2.6.1 web项目
- 概述
可以用于存放web静态资源、web动态资源的项目,可以部署到tomcat服务器中,供外部设备访问
-
项目结构
- index.html
- index.css
- img目录
- girl.jpg
- WEB-INF目录 (必不可少)
- classes目录
- lib目录
- web.xml
-
web.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
</web-app>
2.6.2 tomcat部署web项目
- 语法
http://主机地址:端口号/项目名称/资源名称
-
webapps
- 直接将web项目存放到webapss目录中
-
虚拟目录基础版
- 在tomcat/conf/server.xml中的host标签中,添加如下标签:
<Context docBase="C:\Users\Desktop\mywebproject" path="/fuck"/>
** docBase:项目在磁盘中的路径,path:项目访问的路径**
- 在tomcat/conf/server.xml中的host标签中,添加如下标签:
-
虚拟目录优化版
-
在tomcat/conf/Catalina新建一个fuck.xml文件,内容如下;
<?xml version="1.0" encoding="UTF-8"?>
<Context docBase="C:\Users\Desktop\mywebproject"/>
2.6.2 URL访问资源
浏览器地址中输入URL:http://localhost:8080/服务器名称/index.html
- 经验:URL主要有4部分组成:协议、主机、端口、资源路径
2.6.3 Tomcat响应流程图
2.7 常见错误
2.7.1 Tomcat控制台闪退
闪退问题是由于JAVA_HOME配置导致的,检查JAVA_HOME配置是否正确
2.7.2 404错误
一般是访问资源不存在,才会出现404错误。请检查访问的路径是否输入错误
三 、Servlet基础
3.1 概述
- Servlet:Server Applet的简称,是服务器端的程序(代码、功能实现),可交互式的处理客户端发送到服务端的请求,并完成操作响应。
- 动态网页技术
- JavaWeb程序开发的基础,JavaEE规范(一套接口)的一个组成部分。
- 实现Servlet有三种方式:实现Servlet接口、继承GenericServlet、继承HttpServlet
- Servlet生命周期的方法:init、service、destroy。
3.1.1 Servlet作用
- 接收客户端请求,完成操作。(比如接受前端注册请求完成注册保存数据操作)
- 动态生成网页(页面数据可变)。
- 将包含操作结果的动态网页响应给客户端。
四、IDEA创建Web项目
- 通过项目演示效果:当用户从前端发送url请求时,由servlet接受请求进行处理打印输出语句
4.1 IDEA创建Web项目
- 创建项目窗口,选择JavaEE7,并勾选Web Application
- 输入项目名称和项目保存位置,点击Finish,完成项目创建
- Web项目目录介绍
4.2 IDEA开发Servlet
- 使用开发工具编写Servlet,仍要手工导入servlet-api.jar文件,并与项目关联。
4.2.1 编写Servlet
- 创建MyServlet,实现Servlet接口,覆盖5个方法
4.2.2 配置web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
<!--1添加servlet节点 -->
<servlet>
<servlet-name>MyServlet</servlet-name> --别名
<servlet-class>com.qf.servlet.MyServlet</servlet-class> --指明对应servlet类
</servlet>
<!--2添加servlet映射路径 -->
<servlet-mapping>
<servlet-name>MyServlet</servlet-name> -- 别名
<url-pattern>/myservlet</url-pattern> ---路径名
</servlet-mapping>
</web-app>
4.3 IDEA部署Web项目
4.3.1 IDEA集成Tomcat
- 点击File选项,选择Settings
- 选择Build, Execution, Deployment下的Application Servers。
- 点击+号,选择Tomcat Server
- 选择Tomcat安装目录,点击OK即可
- 最后,点击OK
4.3.2 项目部署Tomcat
- 点击 Add Configuration
- 点击+号,选择Tomcat Server,选择Local
- 点击+号 ,选择 Artifact,添加当前项目
- 点击运行按钮,即可运行项目
4.4 其他操作
4.4.1 关联第三方jar包
-
在WEB-INF目录下新建lib目录
-
输入lib目录
-
复制jar包到lib目录中
- 右击lib目录,选择Add as Library…
- 选择Project Library,完成。
- Global Library 表示所有工程都可以使用。
- Project Library 表示当前工程中所有模块都可以使用。
- Module Library 表示当前模块可以使用。
五、HTTP协议
5.1 什么是HTTP
- 超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议,是一个基于请求与响应模式的、无状态的、应用层的协议,运行于TCP协议基础之上。
5.2 HTTP协议特点
-
支持客户端(浏览器)/服务器模式。
-
简单快速:客户端只向服务器发送请求方法和路径,服务器即可响应数据,因而通信速度很快。请求方法常用的有GET、POST等。
-
灵活:HTTP允许传输任意类型的数据,传输的数据类型由Content-Type标识。
-
无连接:无连接指的是每次TCP连接只处理一个或多个请求,服务器处理完客户的请求后,即断开连接。采用这种方式可以节省传输时间。
- HTTP1.0版本是一个请求响应之后,直接就断开了。称为短连接。
- HTTP1.1版本不是响应后直接就断开了,而是等几秒钟,这几秒钟之内有新的请求,那么还是通过之前的连接通道来收发消息,如果过了这几秒钟用户没有发送新的请求,就会断开连接。称为长连接。
5.3 HTTP协议通信流程
- 客户与服务器建立连接(三次握手)。
- 客户向服务器发送请求。
- 服务器接受请求,并根据请求返回相应的文件作为应答。
- 客户与服务器关闭连接(四次挥手)。
5.4 http请求
- 请求行
- 请求路径
- 请求方式
- 请求头
- Content-Type : 告知服务器,请求正文的mime类型
- Content-Length : 告知服务器,请求正文的长度
- User-Agent : 告知服务器,浏览器相关信息
- Cookie : cookie信息,非常重要
- 请求正文
- 只有post请求才有
5.5 常见状态码
六、Servlet详解
6.1 Servlet核心接口和类
- 在Servlet体系结构中,除了实现Servlet接口,还可以通过继承GenericServlet 或 HttpServlet类,完成编写。
6.1.1 Servlet接口
-
在Servlet API中最重要的是Servlet接口,所有Servlet都会直接或间接的与该接口发生联系,或是直接实现该接口,或间接继承自实现了该接口的类。
-
该接口包括以下五个方法:
- init(ServletConfig config) :servlet生命周期方法
- ServletConfig getServletConfig() :获取ServletConfig对象
- service(ServletRequest req,ServletResponse res) :处理请求,处理响应
- String getServletInfo()
- destroy( ) :servlet生命周期方法
6.1.2 GenericServlet抽象类
- GenericServlet 使编写 Servlet 变得更容易。它提供生命周期方法 init 和 destroy 的简单实现,要编写一般的 Servlet,只需重写抽象 service 方法即可。
6.1.3 HttpServlet类
- HttpServlet是继承GenericServlet的基础上进一步的扩展。
- 提供将要被子类化以创建适用于 Web 站点的 HTTP servlet 的抽象类。HttpServlet 的子类至少必须重写一个方法,该方法通常是以下这些方法之一:
- service方法:处理http请求、处理http响应
- doGet方法:由service方法调用,处理get请求
- doPost方法:由service方法嗲用,处理post请求
6.2 Servlet两种创建方式
6.2.1 实现接口Servlet(不推荐)
/**
* Servlet创建的第一种方式:实现接口Servlet
* */
public class HelloServlet2 implements Servlet{
@Override
public void destroy() {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void init(ServletConfig arg0) throws ServletException {
}
@Override
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
System.out.println("OK");
//响应
response.getWriter().println("welcome use servlet");
}
}
6.2.2 继承HttpServlet(推荐)
/**
* Servlet implementation class HelloServlet
* Servlet的第二种创建方式,继承HttpServlet.也是开发中推荐的
*
*/
public class HelloServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().print("welcome use servlet");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
6.2.3 常见错误
- HTTP Status 404 资源找不到 。
- 第一种情况:地址书写错误。
- 第二种情况:地址没有问题,把IDEA项目中out目录删除,然后重新运行。
- Serlvet地址配置重复。
- Serlvet地址配置错误。比如没有写/
6.3 Servlet两种配置方式
6.3.1 使用web.xml(Servlet2.5之前使用)
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
<display-name>Web_Day11</display-name>
<!--Servlet的第二种配置 -->
<!--Servlet配置 -->
<servlet>
<!--名称 -->
<servlet-name>hello2</servlet-name>
<!--Servlet的全称类名 -->
<servlet-class>com.qf.web.servlet.HelloServlet</servlet-class>
<!--启动的优先级,数字越小越先起作用 -->
<load-on-startup>1</load-on-startup>
</servlet>
<!--映射配置 -->
<servlet-mapping>
<!--名称 -->
<servlet-name>hello2</servlet-name>
<!--资源的匹配规则:精确匹配 -->
<url-pattern>/hello2</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>login.html</welcome-file>
</welcome-file-list>
</web-app>
- 一个servlet是可以有多个访问路径
- 匹配三种方式
- 完全匹配
- 必须以“/”开头
- 目录匹配
- 必须以"/“开头,必须以“”结束,比如:"/a/b/c/”,前面必须是"/a/b/c",后面随便写
- 后缀名匹配
- 必须以""开头,必须以后缀名结束,比如:“.xyz”,前面随便写,后面必须是xyz
- 完全匹配
6.3.2 使用注解@WebServlet (Servlet3.0后支持,推荐)
- 注解常用属性
- name: Serlvet名字 (可选)
- value: 配置url路径
/**
* Servlet implementation class HelloServlet
* 演示Servlet注解式配置
*/
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().print("OK");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
6.3.3 缺省servlet
- 概述
- 如果访问路径为"/"的servlet就是缺省servlet
- 作用
- 处理那些没有匹配上的资源
- 处理静态资源
- 代码实现
- MyDefaultServlet.java
public class MyDefaultServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("MyDefaultServlet");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
- web.xml
<!--覆盖缺省Servlet-->
<servlet>
<servlet-name>MyDefaultServlet</servlet-name>
<servlet-class>com.qfedu.servlet.MyDefaultServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyDefaultServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
七、Servlet应用
7.1 request对象
- 浏览器发起请求,服务器会创建一个request请求对象,并通过servlet中的service方法传入给servlet。
- 可以获取请求参数名、请求参数值、属性、输入流等等
7.1.1 get和post区别
get请求
- get提交的数据会放在URL之后,以?分割URL和传输数据,参数之间以&相连
localhost:8080/day92pm/myservlet?username=zs&age=13 - get方式明文传递,数据量小,不安全
- 效率高,浏览器默认请求方式为GET请求
- 对应的Servlet的方法是doGet
post请求
- post方法是把提交的数据放在HTTP包的Body中
- 密文传递数据,数据量大,安全
- 效率相对没有GET高
- 对应的Servlet的方法是doPost
7.1.2 request对象方法
-
方法说明
-
获取请求头方法
- getHeader
- getHeaders
- getHeaderNames
-
获取请求参数的方法
getParameter : 获取指定参数的值
getParameterValues :获取指定参数的一组值
getParameterNames : 获取所有参数名称
getParameterMap : 获取所有参数名称及对应的一组值,将它们封装到map
7.1.3 get请求收参问题
- 产生乱码是因为服务器和客户端沟通的编码不一致造成的,因此解决的办法是:在客户端和服务器之间设置一个统一的编码,之后就按照此编码进行数据的传输和接收
7.1.4 get中文乱码
在Tomcat7及以下版本,客户端以UTF-8的编码传输数据到服务器端,而服务器端的request对象使用的是ISO8859-1这个字符编码来接收数据,服务器和客户端沟通的编码不一致因此才会产生中文乱码的。
-
解决办法:在接收到数据后,先获取request对象以ISO8859-1字符编码接收到的原始数据的字节数组,然后通过字节数组以指定的编码构建字符串,解决乱码问题。
-
Tomcat8的版本中get方式不会出现乱码了,因为服务器对url的编码格式可以进行自动转换。
-
代码演示
/**
* Servlet implementation class HelloServlet
* 演示Servlet的GET请求,中文乱码的问题
*
*/
@WebServlet("/GETServlet")
public class GetServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取表单提交的姓名
String name=request.getParameter("name");
name=new String(name.getBytes("ISO8859-1"),"UTF-8");
//获取年龄
String age=request.getParameter("age");
//服务端输出打印
System.out.println(request.getRemoteAddr()+"发来信息:姓名:"+name+"---->年龄:"+age);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
7.1.5 post中文乱码
由于客户端是以UTF-8字符编码将表单数据传输到服务器端的,因此服务器也需要设置以UTF-8字符编码进行接收。
-
解决方案:使用从ServletRequest接口继承而来的setCharacterEncoding(charset)方法进行统一的编码设置。
-
代码演示
/**
* Servlet implementation class HelloServlet
* 演示Servlet的GET请求,中文乱码的问题
*
*/
@WebServlet("/GETServlet")
public class GetServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置请求参数的编码格式--对GET无效
request.setCharacterEncoding("UTF-8");
//获取表单提交的信息
String name=request.getParameter("msg");
//服务端输出打印
System.out.println(request.getRemoteAddr()+"发来信息:"+msg);
}
}
7.1.6请求对象作为域对象
-
域对象
- 保存数据,并实现数据在多个资源之间共享。比如:ServletContext(整个web应用)
-
生命周期
- 出生 : 浏览器发起请求
- 存活 : 执行请求
- 死亡 : 返回响应
-
注意事项
- request域对象的作用范围在一次请求中!!!
7.2 response对象
- 概述
浏览器发起请求,服务器处理完请求后,将结果通过响应对象返回给浏览器。
发送字节数据、发送字符数据等等,设置响应信息
- response主要方法
- 代码实现
@WebServlet("/demo12")
public class Demo12Servlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//服务器编码(iso8859-1): login成功 -> 字节
//浏览器解码(utf-8?): 字节 -> login??
//解决请求参数中文乱码 : 告诉服务器以utf-8对请求正文进行解码
request.setCharacterEncoding("utf-8");
//解决响应中文乱码:告诉服务器以utf-8对响应正文进行编码 , 且告诉浏览器以utf-8对响应正文进行解码
// response.setCharacterEncoding("utf-8");
// response.setHeader("Content-Type","text/html;charset=utf-8");
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter();
String username = request.getParameter("username");
String password = request.getParameter("password");
if ("root".equals(username) && "root".equals(password)) {
//登录成功
writer.write("login成功");
} else {
//登录失败
writer.write("login失败");
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
-
response对象之自制图片验证码
-
代码实现
public class ImageCodeUtil {
private static String codeNum;//验证码
/**
* 获取验证码图片
*
* @return
*/
public static BufferedImage getBufferedImage() {
int charNum = 4;
int width = 30 * 4;
int height = 30;
//1,创建内存对象
BufferedImage bufferedImage = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
//2,获取绘图对象
Graphics graphics = bufferedImage.getGraphics();
//3,绘制背景颜色
graphics.setColor(Color.LIGHT_GRAY);
graphics.fillRect(0, 0, width, height);
//绘制边框
graphics.setColor(Color.BLUE);
graphics.drawRect(0, 0, width - 1, height - 1);
//设置验证码文字样式
graphics.setColor(Color.BLACK);
graphics.setFont(new Font("宋体", Font.BOLD, 23));
//设置验证码文字内容
Graphics2D graphics2d = (Graphics2D) graphics;
String s = "ABCDEFGHIGKLMNOPQRSTUVWXYZ";
Random random = new Random();
String msg = "";
int x = 5;
for (int i = 0; i < 4; i++) {
int index = random.nextInt(26);//0-25
String content = String.valueOf(s.charAt(index));
msg += content;
double theta = random.nextInt(45) * Math.PI / 180;
graphics2d.rotate(theta, x, 18);
graphics2d.drawString(content, x, 18);
graphics2d.rotate(-theta, x, 18);
x += 30;
}
codeNum = msg;
//释放资源
graphics.dispose();
// ImageIO.write(bufferedImage, "jpg", response.getOutputStream());
return bufferedImage;
}
/**
* 返回验证码
*
* @return
*/
public static String getCodeNum() {
return codeNum;
}
}
- Demo13Servlet
@WebServlet("/demo13")
public class Demo13Servlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
BufferedImage bufferedImage = ImageCodeUtil.getBufferedImage();
ImageIO.write(bufferedImage,"jpg",response.getOutputStream());
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
-
response对象之控制缓存
-
代码实现
@WebServlet("/demo14")
public class Demo14Servlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Demo14Servlet");
response.setDateHeader("Expires",System.currentTimeMillis() + 1 * 60 * 60 * 1000);
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("你好世界");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
}
-
响应对象之定时刷新
-
代码实现
@WebServlet("/demo15")
public class Demo15Servlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//解决请求参数中文乱码 : 告诉服务器以utf-8对请求正文进行解码
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter();
String username = request.getParameter("username");
String password = request.getParameter("password");
if ("root".equals(username) && "root".equals(password)) {
//登录成功
writer.write("login成功");
} else {
//登录失败,过3秒后,跳转到login.html
response.getWriter().write("login失败,3秒后跳转到登录页面");
response.setHeader("Refresh","3;URL=/day32/login.html");
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
八、 转发与重定向
8.1 转发
- xxServlet收到请求,然后直接转发给yyServlet,然后yyServlet返回给客户端。整个过程 中,客户端发出一个请求,收到一个响应。
- 转发的作用在服务器端,将请求发送给服务器上的其他资源,以共同完成一次请求的处理。
8.1.1 页面跳转
-
在调用业务逻辑的Servlet中,编写以下代码
-
request.getRequestDispatcher("/目标URL-pattern").forward(request, response);
- 使用forward跳转时,是在服务器内部跳转,地址栏不发生变化,属于同一次请求
8.1.2 数据传递
forward表示一次请求,是在服务器内部跳转,可以共享同一次request作用域中的数据
- request作用域:拥有存储数据的空间,作用范围是一次请求有效(一次请求可以经过多次转发)
- 可以将数据存入request后,在一次请求过程中的任何位置进行获取
- 可传递任何数据(基本数据类型、对象、数组、集合等)
- 存数据:request.setAttribute(key,value);
- 以键值对形式存储在request作用域中。key为String类型,value为Object类型
- 取数据:request.getAttribute(key);
- 通过String类型的key访问Object类型的value
8.1.3 转发特点
- 转发是服务器行为
- 转发是浏览器只做了一次访问请求
- 转发浏览器地址不变
- 转发两次跳转之间传输的信息不会丢失,所以可以通过request进行数据的传递.
8.2 重定向
- 重定向作用在客户端,客户端将请求发送给服务器后,服务器响应给客户端一个新的请求地址,客户端重新发送新请求。
8.3.1 页面跳转
在调用业务逻辑的Servlet中,编写以下代码
-
response.sendRedirect(“目标URI”);
-
URI:统一资源标识符(Uniform Resource Identifier),用来表示服务器中定位一个资源,资源在web项目中的路径(/project/source)
- 使用redirect跳转时,是在客户端跳转,地址栏发生变化,属于多次请求
8.2.2 数据传递
sendRedirect跳转时,地址栏改变,代表客户端重新发送的请求。属于两次请求
- response没有作用域,两次request请求中的数据无法共享
- 传递数据:通过URI的拼接进行数据传递("/WebProject/b?username=tom");
- 获取数据:request.getParameter(“username”);
8.3.3 重定向特点
- 重定向是客户端行为。
- 重定向是浏览器做了至少两次的访问请求。
- 重定向浏览器地址改变。
- 重定向两次跳转之间传输的信息会丢失(request范围)。
- 重定向可以指向任何的资源,包括当前应用程序中的其他资源、同一个站点上的其他应用程序中的资源、其他站点的资源。
8.3 转发、重定向总结
- 当两个Servlet需要传递数据时,选择forward转发。不建议使用sendRedirect进行传递
九、 Servlet生命周期
9.1 生命周期四个阶段
9.1.1 实例化
- 当用户第一次访问Servlet时,由容器调用Servlet的构造器创建具体的Servlet对象。也可以在容器启动之后立刻创建实例。使用如下代码可以设置Servlet是否在服务器启动时就创建。
<load-on-startup>1</load-on-startup>
- 注意:只执行一次
9.1.2 初始化
-
在初始化阶段,init()方法会被调用。这个方法在javax.servlet.Servlet接口中定义。其中,方法以一个ServletConfig类型的对象作为参数。
-
注意:init方法只被执行一次
9.1.3 服务
-
当客户端有一个请求时,容器就会将请求ServletRequest与响应ServletResponse对象转给Servlet,以参数的形式传给service方法。
-
此方法会执行多次
9.1.4 销毁
-
当Servlet容器停止或者重新启动都会引起销毁Servlet对象并调用destroy方法。
-
destroy方法执行一次
9.1.5 Servlet执行流程
- 代码演示
/**
* Servlet implementation class LifeServlet
* 演示Servlet的生命周期:
* 1、实例化
* 2、init:初始化
* 3、service:服务
* 4、destory:销毁
*/
@WebServlet("/lifeservlet")
public class LifeServlet extends HttpServlet {
public LifeServlet() {
super();
System.out.println("1、完成了实例化");
}
@Override
public void init() throws ServletException {
super.init();
System.out.println("2、完成了初始化");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("3、就绪中");
response.getWriter().append("Served at: ").append(request.getContextPath());
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
@Override
public void destroy() {
super.destroy();
System.out.println("4、销毁了");
}
}
十、Cookie的使用
10.1 什么是Cookie
-
Cookie是在浏览器访问Web服务器的某个资源时,由Web服务器在HTTP响应消息头中附带传送给浏览器的一小段数据。
-
一旦我们的Web浏览器保存了某个Cookie,那么它在以后每次访问该Web服务器时,都应在HTTP请求头中将这个Cookie回传给Web服务器。
-
一个Cookie主要由标识该信息的名称(name)和值(value)组成。
-
每个web应用最多支持20个cookie,每个浏览器最多支持300个cookie,每个cookie最大为4KB
10.2 Cookie 有什么作用?
-
计算机 cookie 的目的是帮助网站跟踪您的访问和活动。这并不总是坏事。例如,许多在线零售商在浏览网站时使用 cookie 来跟踪用户购物车中的商品。如果没有 Cookie,每次点击网站上的新链接时,您的购物车都会重置为零。这将使在线购买任何东西变得困难!
-
网站也可能使用 cookie 来记录您最近的访问记录或记录您的登录信息。许多人发现这很有用,因此他们可以在常用网站上存储账户和密码
10.3 创建Cookie
//创建Cookie
Cookie ck=new Cookie("code", code);
ck.setMaxAge(-1);//内存存储,取值有三种:>0有效期,单位秒;=0浏览器关闭;<0内存存储,默认-1
response.addCookie(ck);//添加到response对象中,响应时发送给客户端
- chrome浏览器查看cookie信息:chrome://settings/content/cookies
10.4 cookie执行流程
- 执行流程
- 浏览器端第一次发起请求,服务器端创建cookie对象
- 响应对象通过操作响应头“Set-Cookie”将cookie信息携带到浏览器端
- 浏览器端拿到该cookie信息保存到本地
- 浏览器端第二次发起请求,cookie信息会随着请求头“cookie”携带到服务器端
- 服务器端通过request.getCookies()方法来获取该cookie信息
10.5 获取Cookie
//获取所有的Cookie
Cookie[] cks=request.getCookies();
//遍历Cookie
for(Cookie ck:cks){
//检索出自己的Cookie
if(ck.getName().equals("code"))
{
}
}
-
案例:模拟用户登录成功后,把账户密码保存在cookie中30秒。30秒内进行访问地址可以直接从客户端的cookie中获取到账号密码。30s后则获取不好
-
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="login" method="post">
用户名:<input type="text" name="username" /><br/>
密码:<input type="password" name="password"><br/>
<input type="submit" value="登录" />
</form>
</body>
</html>
- MyLoginServlet
@WebServlet("/login")
public class MyLoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取账户密码
String username = req.getParameter("username");
String password = req.getParameter("password");
//判断登录正确时把账号和密码保存在浏览器的cookie中
if (username.equals("zs")&&password.equals("123")){
Cookie a = new Cookie("username", username);
Cookie b = new Cookie("password", username);
a.setMaxAge(30);//设置时间
b.setMaxAge(30);
resp.addCookie(a);//保存在浏览器中
resp.addCookie(b);
resp.getWriter().println("ok!");
}else{
resp.getWriter().println("no!");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
-
MyCookieServlet
-
在登录成功后30秒可以直接通过访问denglu路径从客户端浏览器中获取到账号和密码,(利用此特点以后我们可以做记住密码功能)
@WebServlet("/denglu")
public class MyCookieServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Cookie[] cookies = request.getCookies();
String username=null;
String password=null;
for(Cookie co:cookies){
if (co.getName().equals("username")){
username=co.getName();
}
if (co.getName().equals("password")){
password=co.getName();
}
}
System.out.println(username+"===="+password);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
十一、Session对象
11.1 Session概述
- Session用于记录用户的状态。Session指的是在一段时间内,单个客户端与Web服务器的一连串相关的交互过程。
- 在一个Session中,客户可能会多次请求访问同一个资源,也有可能请求访问各种不同的服务器资源。
- session是基于cookie的,cookie中保存了session的唯一标识,请求时会携带该唯一标识到服务器
- session也叫会话对象,那什么是会话呢?
例如打电话,从打通的那一刻开始,会话就i产生了,知道挂断电话。
在网络上比如登录,从登录成功的那刻开始,会话就产生了,只有发生二种情况会话才会销毁:1.退出登录2.关闭浏览器。在登录的中的整个过程都是属于会话
在同一个会话中,session域中的资源数据会被共享,不同页面共享改会话中的所有内容。
比如在你登录淘宝成功后,会话就开始了,然后你会发现在登录的过程中无论你访问的哪一个淘宝页面都有欢迎您XXX的用户名信息,说明在你已经登陆的时候就把你的账户信息设置在了session作用域中,从而使每一个不同的页面都可以显示你的信息。
11.2 Session原理
-
服务器会为每一次会话分配一个Session对象
-
同一个浏览器发起的多次请求,同属于一次会话(Session)
-
注意:session是由服务端创建的。
11.3 Session使用
- Session作用域:拥有存储数据的空间,作用范围是一次会话有效
- 一次会话是使用同一浏览器发送的多次请求。一旦浏览器关闭,则结束会话
- 可以将数据存入Session中,在一次会话的任意位置进行获取
- 可传递任何数据(基本数据类型、对象、集合、数组)
获取Session
- session是服务器端自动创建的,通过request对象获取
//获取Session对象
HttpSession session=request.getSession();
System.out.println("Id:"+session.getId());//唯一标记,
Session保存数据
//setAttribute(属性名,Object)保存数据到session中
session.setAttribute("key",value);//以键值对形式存储在session作用域中。
Session获取数据
//getAttribute(属性名);获取session中数据
session.getAttribute("key");//通过String类型的key访问Object类型的value
Session移除数据
//removeAttribute(属性名);从session中删除数据
session.removeAttribute("key");//通过键移除session作用域中的值
Session销毁
session.invalidate();
11.4 session执行流程
- 执行流程
- 浏览器第一次请求,request.getSession方法会直接创建一个session对象,通过响应头Set-Coolie将该session对象的唯一标识携带到浏览器保存
- 浏览器第二次请求,session的唯一标识会随着cookie请求头携带到服务器
- 服务器会根据该session的唯一标识在服务器中有没有匹配的session对象,如果有直接使用,如果没有就创建session对象。
11.5 Session作用域与Request作用域的区别
- request是一次请求有效,请求改变,则request改变
- session是一次会话有效,浏览器改变,则session改变
11.6 Session的生命周期
- 开始:第一次使用到Session的请求产生,则创建Session
- 结束:
- 浏览器关闭,则失效
- Session超时,则失效
- session.setMaxInactiveInterval(seconds);//设置最大有效时间(单位:秒)
- 默认30分
- 手工销毁,则失效
- session.invalidate();//登录退出、注销
十二、ServletContext对象
12.1 ServletContext概述
- 全局对象,也拥有作用域,对应一个Tomcat中的Web应用
- 当Web服务器启动时,会为每一个Web应用程序创建一块共享的存储区域(ServletContext)。
- ServletContext在Web服务器启动时创建,服务器关闭时销毁。
12.2 获取ServletContext对象
- GenericServlet提供了getServletContext()方法。(推荐) this.getServletContext();
- HttpServletRequest提供了getServletContext()方法。(推荐)
- HttpSession提供了getServletContext()方法。
12.3 ServletContext作用
12.3.1 获取项目真实路径
-
获取当前项目在服务器发布的真实路径
String realpath=servletContext.getRealPath("/");
12.3.2 获取项目上下文路径
-
获取当前项目上下文路径(应用程序名称)
System.out.println(servletContext.getContextPath());//上下文路径(应用程序名称)
System.out.println(request.getContextPath());
12.3.3 全局容器
- ServletContext拥有作用域,可以存储数据到全局容器中
- 存储数据:servletContext.setAttribute(“name”,value);
- 获取数据:servletContext.getAttribute(“name”);
- 移除数据:servletContext.removeAttribute(“name”);
12.4 ServletContext特点
- 唯一性: 一个web应用对应一个ServletContext。
- 生命周期: 只要容器不关闭或者应用不卸载,ServletContext就一直存在。
12.5 ServletContext应用场景
- ServletContext统计当前项目访问次数
代码演示:
/**
* Servlet implementation class Servlet3
*/
@WebServlet("/servlet3")
public class Servlet3 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
ServletContext application = request.getServletContext();
Integer count=(Integer) application.getAttribute("count");
if(count==null) {
count=1;
application.setAttribute("count", count);
}else {
count++;
application.setAttribute("count", count);
}
PrintWriter out=response.getWriter();
out.write("servlet共访问次数:"+count);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
12.6 三大作用域总结
- HttpServletRequest:一次请求,请求响应之前有效
- HttpSession:一次会话开始,浏览器不关闭或不超时之前有效
- ServletContext:服务器启动开始,服务器停止之前有效
十三、过滤器
概述
- 过滤器(Filter)是处于客户端与服务器目标资源之间的一道过滤技术。
- 一个可以对请求和响应进行过滤的组件.
- 过滤器中包含了一个FilterConfig对象,可以获取过滤器的初始化参数
13.1 过滤器作用
- 执行地位在Servlet之前,客户端发送请求时,会先经过Filter,再到达目标Servlet中;响应时,会根据执行流程再次反向执行Filter
- 可以解决多个Servlet共性代码的冗余问题(例如:乱码处理、登录验证)
13.2 编写过滤器
Servlet API中提供了一个Filter接口,开发人员编写一个Java类实现了这个接口即可,这个Java类称之为过滤器(Filter)
13.2.1 实现过程
- 编写Java类实现Filter接口
- 在doFilter方法中编写拦截逻辑
- 设置拦截路径
@WebFilter("/MyFilter1")//过滤路径
public class MyFilter1 implements Filter {
//初始化过滤器
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("过滤器初始化了........init... "+filterConfig);
}
//执行过滤
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("过滤前........doFilter ");
//放行
chain.doFilter(request, response);
System.out.println("过滤后.......doFilter");
}
//销毁
@Override
public void destroy() {
System.out.println("销毁了.....destroy");
}
}
13.3 过滤器配置
13.3.1 注解配置
- 在自定义的Filter类上使用注解@WebFilter(value=“/过滤目标资源”)
13.3.2 xml配置
<!--过滤器的xml配置 -->
<filter>
<!--名称-->
<filter-name>sf</filter-name>
<!--过滤器类全称-->
<filter-class>com.qf.web.filter.SecondFilter</filter-class>
</filter>
<!--映射路径配置-->
<filter-mapping>
<!--名称-->
<filter-name>sf</filter-name>
<!--过滤的url匹配规则和Servlet类似-->
<url-pattern>/*</url-pattern>
</filter-mapping>
13.3.3 过滤器路径
过滤器的过滤路径通常有三种形式:
精确过滤匹配 ,比如/index.jsp /myservlet1
后缀过滤匹配,比如*.jsp、.html、.jpg
通配符过滤匹配/*,表示拦截所有。
13.4 过滤器链和优先级
13.4.1 过滤器链
-
客户端对服务器请求之后,服务器调用Servlet之前会执行一组过滤器(多个过滤器),那么这组过滤器就称为一条过滤器链。
-
每个过滤器实现某个特定的功能,当第一个Filter的doFilter方法被调用时,Web服务器会创建一个代表Filter链的FilterChain对象传递给该方法。在doFilter方法中,开发人员如果调用了FilterChain对象的doFilter方法,则Web服务器会检查FilterChain对象中是否还有filter,如果有,则调用第2个filter,如果没有,则调用目标资源。
13.4.2 过滤器优先级
- 在一个Web应用中,可以开发编写多个Filter,这些Filter组合起来称之为一个Filter链。
优先级:
- 如果为注解的话,是按照类全名称的字符串顺序决定作用顺序
- 如果web.xml,按照 filter-mapping注册顺序,从上往下
- web.xml配置高于注解方式
- 如果注解和web.xml同时配置,会创建多个过滤器对象,造成过滤多次。
13.5 过滤器典型应用
13.5.1 过滤器解决编码
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter(value = "/*")
public class EncodingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//统一处理请求和响应的乱码
servletRequest.setCharacterEncoding("UTF-8");
servletResponse.setContentType("text/html;charset=utf-8");
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
13.5.2 权限验证
- ShowAllAdminController
@WebServlet(value = "/showallcontroller")
public class ShowAllAdminController extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
AdminService adminService = new AdminServiceImpl();
List<Admin> adminList = adminService.showAllAdmin();
//request作用域存储数据
req.setAttribute("admins",adminList);
//通过转发 跳转到显示结果servlet
req.getRequestDispatcher("/showalljsp").forward(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
- CheckFilter
@WebFilter(value = "/showallcontroller")
public class CheckFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//权限验证 验证管理员是否登录!
//向下转型 拆箱
HttpServletRequest request = (HttpServletRequest)servletRequest;
HttpServletResponse response = (HttpServletResponse)servletResponse;
HttpSession session =request.getSession();
Manager mgr = (Manager) session.getAttribute("mgr");
if(mgr!=null){//登录过!
filterChain.doFilter(request,response);
}else{
response.sendRedirect(request.getContextPath()+"/loginMgr.html");
}
}
@Override
public void destroy() {
}
}
十四、监听器
- 概述
- 事件源:事件发生的源头
- 监听器:监听事件发生的组件
- 绑定:将事件源和监听器关联起来
- 事件:能够出发监听器的事
- servlet监听器
- 事件源:Servlet的三大域对象
- 监听器:三类监听器
- 绑定:web.xml配置、注解配置
- 事件:域对象状态、内容发生改变
14.2 监听器的分类
- 一类监听器
- 监听域对象的创建、销毁
- 二类监听器
- 监听域对象中的数据改变
- 三类监听器
- 监听域对象中的java对象的绑定、解绑