Servlet
1.maven介绍
在讲解servlet之前,有必要先了解一下maven,关于maven的介绍以及配置使用,请前往我的这篇笔记学习Maven的介绍与安装配置以及依赖
有了maven的基础,我们就可以正式进入servlet了吖~~
2. 创建servlet
2.1 servlet依赖导入maven
新建一个空的maven项目,将servlet的依赖给导入pom.xml文件中
<dependencies>
<!-- 每一个依赖都是写在一对<dependency></dependency>里面的,并且在<dependencies></dependencies>中-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
<!--
compile:默认的scope,运行期有效,需要打入包中
provided:编译期有效,运行期不需要提供,不会打入包中
runtime:编译不需要,在运行期有效,需要导入包中。(接口与实现分离)
test:测试需要,不会打入包中
system:非本地仓库引入、存在系统的某个路径下的jar。(一般不使用)
-->
</dependency>
</dependencies>
注意:在创建使用servlet等包的时候,是需要将servlet的依赖给导入maven项目中的,这样才可以被使用,具体的依赖找不到的话,可以直接在下面这个网站上maven依赖链接直接搜索自己想要的,然后给cv到pom.xml中即可。同时也要导入适合自己tomcate版本的依赖哦~
2.2 servlet类的创建
servlet类的创建有三种方式:
- 实现 javax.servlet.Servlet 接口,重写其全部方法。
- 继承 javax.servlet.GenericServlet 抽象类,重写 service() 方法。
- 继承 javax.servlet.http.HttpServlet 抽象类,重写 doGet() 或 doPost() 方法。
虽然servlet的创建有三种方式,但是现在我们都是用方法3,因为三者是存在实现与继承关系的,要是用一或二需要重写的方法就会很多,会造成代码冗余的情况,可以看一下三者的关系:
由图我们可以知道:
- GenericServlet 是实现了 Servlet 接口的抽象类。
- HttpServlet 是 GenericServlet 的子类,具有 GenericServlet 的一切特性。
- Servlet 程序(MyServlet 类)是一个实现了 Servlet 接口的 Java 类。
所以我们平时创建servlet的时候都是采用继承javax.servlet.http.HttpServlet 抽象类来完成的
现在我们来创建一个servlet类试试手~
- 创建一个UserController的servlet类
- 配置web.xml文件
- 完成一个servlet类的创建
第一步:创建servlet类
package com.xiaowang.createServlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @Author:小王吖
* @Date:2022/10/12
*/
public class UserController extends HttpServlet {
//如果请求是doGet请求会执行doGet
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
}
//如果请求是post请求会执行doPost
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
2.3 servlet的配置
servlet的配置由两种方式,不同的方式有不同的好处,下面来介绍下两种方式
2.3.1 web.xml配置
第二步:配置web.xml文件
无注释版本:
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<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"
metadata-complete="false">
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>UserContrller</servlet-name>
<servlet-class>com.xiaowang.createServlet.UserController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UserContrller</servlet-name>
<url-pattern>/User</url-pattern>
</servlet-mapping>
</web-app>
有注释版本,介意看有注释版本,这样会对servlet的xml配置更加理解,
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<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"
metadata-complete="false">
<!--注意,这里的配置,要根据自己的toncat和servlet的版本来配置,我的tomcat是9的,所以这里的version="4.0",
tomcat8的是version="3.0",反正就是要根据自己的版本来配置,这里如果不知道自己的是多少,可以去创建一个maven-webapp项目
然后去看那个项目中web.xml中的配置,cv过来就好了-->
<display-name>Archetype Created Web Application</display-name>
<servlet>
<!-- 你的servlet项目的类名-->
<servlet-name>UserContrller</servlet-name>
<!-- servlet项目的路径-->
<servlet-class>com.xiaowang.createServlet.UserController</servlet-class>
</servlet>
<servlet-mapping>
<!-- 你的servlet项目的类名-->
<servlet-name>UserContrller</servlet-name>
<!-- 数据库中要操作的数据库的表名,同时也是我们的实体类,这两个是对应的-->
<url-pattern>/User</url-pattern>
</servlet-mapping>
</web-app>
2.3.2 注解配置
1. 注解解释
- 若项目中 Servelt 数量较多时,web.xml 的配置会变得十分的冗长。这种情况下,注解(Annotation)就是一种更好的选择。
- 注解不需要依赖于配置文件,它可以直接在类中使用,其配置只对当前类有效,这样就避免了集中管理造成的配置冗长问题。
2. 启用注解
- web.xml 的顶层标签 中有一个属性:metadata-complete,该属性用于指定当前 web.xml 是否是完全的。若该属性设置为 true,则容器在部署时将只依赖 web.xml,忽略所有的注解。若不配置该属性,或者将其设置为 false,则表示启用注解支持。
- 由于 metadata-complete 属性的默认值是 false,即默认启用 Servlet 注解支持,所以默认情况下,使用该注解时,不必创建 web.xml 文件。
3. 使用@WebServlet注解
@WebServlet 属于类级别的注解,标注在继承了 HttpServlet 的类之上。常用的写法是将 Servlet 的相对请求路径(即 value)直接写在注解内,如下所示。
//完整写法:
@WebServlet(urlPatterns = "/MyServlet")。
//简写:
@WebServlet("/MyServlet")
服务器具体的操作,就看是去调用哪个方法了
3. 请求HttpServletRequest
1. http协议
- 超文本传输协议(HyperText Transfer protocal)
- 运行在tcp协议上的一次请求和响应协议,指定了客户端给服务器发送or得到的消息
2. 特点
1.基于tcp协议
2.缺省端口80,https基于http协议的基础上再次加密,缺省端口是443
3.基于请求-响应模型:一次请求一定对应一次响应;请求和响应都存在的时候才可以叫做一次完整的http请求
4.无状态:请求之间是相互独立的,不能互相交互数据`
3. 请求消息格式
- 请求行
- 格式:请求方式 请求url 请求协议/版本
- 请求方式
-
Get: 1.参数会直接显示在请求行中,会在url后面暴露出来 2.相对不安全,效率更高一些 3.因为url的长度是有限的,类型为字符串 Chrome的url长度是8182个字符,超过后就返回错误 IE的长度限制2083,超过以后就自动截断(如果使用form那么提交按钮就不会起效果) Apache 服务器 接收长度限制为8192 tomcat 通过配置Connector的maxParamterCount属性去配置长度,默认值是10000 maxPostSize post请求的最大值 nginx 服务器 可以通过修改配置来改变url请求的长度限制 client_header_buffer_size 默认值为1K large_client_header_buffers 默认值是8k
-
POST: 1.参数在请求体中 2.请求url长度和get一样,因为参数不在url中,所以参数大小无限制,参数类型无限制(文件上传的时候选择post请求) 3.相对安全,效率相对低一些
-
请求头
浏览器告诉服务器的一些信息
请求头名称:请求头的值
能够接收的数据类型
-
请求体
就是封装post请求的参数
3.1 请求转发forword
- 是一种服务器内部实现页面跳转的方式
- 浏览器不知道服务器内部发生了什么,所以地址栏不会被改变
- 转发达到目标资源后,目标资源将其进行处理,最后响应返回给浏览器
- 整个过程只有一次请求和转发,是一次完整的http请求
//获取请求转发器,参数就是需要转发到的目的地
RequestDispatcher requestDispatcher = request.getRequestDispatcher("/my");
//执行转发
requestDispatcher.forward(request,response);
- 数据通过域对象(作用域)来共享的
- request(作用域):
- 只在一次http请求中可以共享数据
//需要将数据放入作用域中
request.setAttribute("list",list);
//java代码
List<User> list = (List<User>) request.getAttribute("list");
//移除指定的数据
request.removeAttribute("list");
//获取作用域中所有key的名称 可以通过遍历获取作用域中的所有数据
Enumeration<String> attributeNames = request.getAttributeNames();
- 注意:request作用域只能作用在同一个请求中,不同的请求中是不能共享数据的
3.2 请求乱码处理
客户端发送中文到服务器后,服务器接收到中文可能出现乱码的情况
//get请求乱码
filename = new String(filename.getBytes("ISO-8859-1"),"UTF-8");
// post请求 乱码 这句话必须放在获取参数之前
request.setCharacterEncoding("UTF-8");
4. 响应HttpServletResponse
4.1 基本介绍
将服务器的消息响应给浏览器
1. 响应行
- 协议/版本 响应状态码 状态码描述
HTTP/1.1 200 ok - 响应状态码
服务器发送给客户端用来描述这次请求的一个数字。状态码一般是3位数- 1xx 服务器接收到客户端的消息,但是还没有接收完成,等待一段时间后,发送多个1xx的代码
- 2xx 表示成功 常见200
- 3xx 表示请求的资源已经转移到新的地方,需要客户端去访问新的地址 常见302(资源被临时转移) 301(资源被永久转移) 304(资源被缓存)
- 4xx 表示客户端的请求错误 常见404(资源未找到) 403(请求参数错误) 405(请求方式错误)
- 5xx 服务器错误 常见500(服务器内部错误)
2. 响应头
响应头名称:响应头的值
常见的响应头:
Content-Length: 836 内容长度
Content-Type: text/html; utf-8=;charset=UTF-8 内容类型
Date: Wed, 06 Apr 2022 02:30:35 GMT 响应时间
Server: Apache-Coyote/1.1 服务器
Set-Cookie: JSESSIONID=04FDEF35B648BDC71D4E4544BDB96439; Path=/webtest2/; HttpOnly 响应的cookie
Location: 重定向以后的地址
Content-Disposition: 告诉浏览器响应的内容以什么方式打开
in-line: 默认值,直接在当前页打开
attachment;filename=xxxx 告诉浏览器响应的内容包含了附件 附件名为xxxx 需要以文件下载的方式打开
cache-control: 缓存控制 no-cache 不需要缓存
Refresh: 刷新界面 Refresh:5;url=xxxx 5s后跳转到url指定的路径上去
从上面可以观察到,响应头可以控制浏览器的一部分行为
3. 响应体
服务器响应给客户端的数据
4.2 response对象
这个对象主要就是针对服务器对客户端的响应进行封装的,用doGet举例:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("myServlet");
//服务器响应的数据乱码,加这一句就可以解决
response.setContentType("text/html;charset=utf-8");//设置响应的数据类型
//重定向
/*response.sendRedirect("https://www.baidu.com");//服务器外部
response.setStatus(302);
response.setHeader("Location","https://www.baidu.com");
//服务器内部 前面从项目名开始去进行访问
response.sendRedirect("/webtest2/user/aaa?a=b");*/
//缓存控制
response.setHeader("Cache-Control","no-cache");
response.setHeader("Pragma","no-cache");
//IE 缓存1小时 如果不缓存就直接写0
response.setDateHeader("Expires",System.currentTimeMillis() + 1000 * 60 * 60);
//获取两个输出流 两个流不能同时使用
PrintWriter writer = response.getWriter();//字符流
ServletOutputStream outputStream = response.getOutputStream();//字节流
boolean b = response.containsHeader("");//判断是否包含某个头
// response.encodeRedirectUrl("")//URL重写
Collection<String> headerNames = response.getHeaderNames();//获取所有响应头名称
}
其实就是服务器要响应东西给浏览器的时候,就用response这个对象去调用对应想要的方法传过去即可,同时需要注意代码中的注释部分
4.3 重定向
- 服务器收到浏览器的请求,检查后发现资源被转移,所以就会响应302或者location回去
- 客户端收到了302和location的值后,就会去访问新的地址
- 浏览器是知道地址栏要改变的
- 请求至少两次
- 可以访问服务器外部资源
response.sendRedirect("https://www.baidu.com");//服务器外部
response.setStatus(302);
response.setHeader("Location","https://www.baidu.com");
//服务器内部 前面从项目名开始去进行访问
response.sendRedirect("/webtest2/user/aaa?a=b");
4.4 请求转发和重定向区别
- 请求转发:只有一次请求一次响应,浏览器地址栏不会改变,不能请求外部资源
- 重定向:至少两次请求,地址栏要改变,可以请求外部资源
前后端数据禁止显示js语句,只是文本
将关键字给用<关键字<
来括号起来
con
+