目录
一,Servlet介绍
1,简介
2,Servlet技术特点
3,Servlet在应用程序中的位置
4,Servlet在程序中到底处于一个什么地位?
二,servlet运行过程:
三,servlet路径配置
四,Servlet的生命周期
1,伪单例模式
2,生命周期的步骤
3,讲解Servlet是一个伪单例模式
五,什么是生命周期啊?就是说什么时候有的,以及什么时候没的。
六,HttpServletRequest请求对象
1,获取请求行信息
2,获取请求头信息
3,获取请求体数据
回顾http请求:
七,HttpServletResponse响应对象
1,响应行
2,响应头
(1)设置响应头(setHeader)【解决乱码】
(2)设置同名的响应头(addHeader)——怎么能不覆盖呢?
(3)设置字符型响应
(4)设置字节型响应
(5)设置响应编码
(6)在响应中添加附加信息(文件下载)
3,响应主体
回顾http响应:
八,乱码问题
1,请求数据乱码
2,响应的数据乱码
3,jsp页面乱码
一,Servlet介绍
1,简介
- 是一种web服务器端编程技术
(不要觉得Servlet很神奇,就是一个普通的java类,只不过可以运行在服务器端。在服务器端接收客户端的请求和返回响应信息)
- 是实现了特殊接口的Java类
(一级一级往上找,确实实现了Servlet接口,但是我们用得时候,是继承httpServlet类)
- 一个Servlet负责对应一个或一组URL访问请求,并返回相应的响应内容。
- Servlet是Server Applet的简称,称为服务端小程序,是JavaEE平台下的技术标准,基于Java语言编写的服务端程序。Web容器或应用服务器实现了Servlet标准所以Servlet需运行在Web容器或应用服务器中。Servlet主要功能在于能在服务器中执行并生成数据。
-
Html,css,js在浏览器中执行,在服务器端生成。我们学习的Servlet就是一种在服务器端动态生成html,css,js数据的技术。
-
Servlet对象是伪单例模式;通过map集合实现。(可以延迟创建,也可以立即创建)
使用web.xml 和 注解方式配置Servlet。 -
Servlet作为一种动态资源技术,是我们后续学习框架的基础
2,Servlet技术特点
Servlet使用单进程多线程方式运行。
3,Servlet在应用程序中的位置
4,Servlet在程序中到底处于一个什么地位?
- Servlet是可以接受Http请求并作出相应的一种技术,是JAVA语言编写的一种动态资源
- Servlet是前后端衔接的一种技术,不是所有的JAVA类都可以接收请求和作出相应,Servlet可以
- 在MVC模式中,Servlet作为Controller层(控制层)主要技术,用于和浏览器完成数据交互,控制交互逻辑
- 静态资源和动态资源区分
静态资源: 每次访问都不需要运算,直接就可以返回的资源, 如HTML CSS JS 多媒体文件等等,每次访问获得的资源都是一样的
动态资源:每次访问都需要运算代码生成的资源,如Servlet JSP ,每次访问获得的结果可能都是不一样的
二,servlet运行过程:
- 浏览器发送请求到服务器(用到http协议)
- 服务器根据请求的url,去调用响应的Servlet类(请求)
- 通过Servlet中的打印流对象将生成的html数据输出给服务器(响应)
- 服务器将servlet生成的数据在输出给客户端浏览器(用到http协议)
三,servlet路径配置
在web.xml中配置Servlet的映射路径
<url-pattern>/abcd</url-pattern>只有abcd这一种方式可以访问到hiServlet类。<url-pattern>/aaa/*</url-pattern>
只要是在aaa这个路径下的所有请求都可以访问hiServlet类。<url-pattern>*.bbb</url-pattern>只要是以bbb结尾的路径都可以访问hiServlet类。http://localhost:8080/项目名/asdsafd/asffs/fsfdsgf/sfasdfsa.bbb
http://localhost:8080/项目名/sfasdfsa.bbb都可以
<url-pattern>/ccc/*.bbb</url-pattern>===非法写法!!
四,Servlet的生命周期
1,伪单例模式
单例:一个类只创建一个对象
【servlet是一个伪单例模式,只是借鉴了单例模式的思想,他通过别的途径做的实现】
通过map集合来实现单例效果!因为构造器不是private
2,生命周期的步骤
第一步:实例化
第二步:初始化,
(延迟创建:客户端【第一次】发送请求 ----到该Servlet服务器才会创建该对象)
(立即创建:<load-on-startup>1</load-on-startup>)
第三步:执行服务——》接收请求——》对请求进行分发,给回响应)【反复】
第五步:销毁。(1.服务器关闭的时候,所有Servlet对象都销毁
new | 实例化 |
init() | 初始化 |
service() | 执行服务 |
destroy() | 回收销毁 |
Servlet的生命周期是由容器管理的,分别经历四各阶段:
阶段 次数 时机
创建 1次 第一次请求
初始化 1次 实例化之后
执行服务 多次 每次请求
销毁 1次 停止服务
3,讲解Servlet是一个伪单例模式
(1)创建HelloServlet类,实现5个方法,其中service方法,调用父类的Service方法。
(2)为什么说Servlet是伪单例模式呢?
因为单例模式有3种方式,懒汉式(需要私有构造),饿汉式(需要私有构造),枚举方式。而我们的Servlet中没有枚举,也没有出现私有构造。那是通过什么方式实现单例模式的呢?---map集合方式。
因为运行在servlet容器中,类似于map(key-value)
Map<String,HttpServlet>
Key:String --- (servlet-name)hello
Value:代表Servlet对象通过反射获的。Class.getConstructor(null).newInstance(null);
第一次访问的时候创建新的对象
第二次访问直接使用已有的对象====所以servlet-name的名字不能重复。
(3),在servlet容器中最多只有一个对象(理论上),实际上可以创建多个
(4)那你说Servlet模拟的是懒汉式还是饿汉式啊?
Servlet默认属于懒汉式,第一次访问的时候被载入并初始化;
如果觉得初始化时间较长Servlet可以设置成饿汉式。
---在web.xml中,
<servlet>1<servlet-name>helloServlet</servlet-name><servlet-class>servlet.helloServlet</servlet-class><load-on-startup></load-on-startup>----如果值是正整数就是启动服务就被加载,整数越小越提前加载;如果值是负整数,或者没写这个标签,都是在第一次访问的时候加载。</servlet>
五,什么是生命周期啊?就是说什么时候有的,以及什么时候没的。
什么时候有的:第一次访问的时候(默认)
什么时候没的:服务器关闭,而不是调用destory();调用destory()方法只是为了在销毁之前,在做一些工作。不需要我们手动调用,服务器会给我们自动调用。
- 在Servlet中我们一般不要轻易使用成员变量!!!! 可能会造成线程安全问题
- 如果要使用的话,应该尽量避免对成员变量产生修改
- 如果要产生修改我们应该注意线程安全问题
- 如果我们自己添加线程安全编码处理,会严重影响效率
- 综上所述:原则,能不用成员变量就不用!!!
六,HttpServletRequest请求对象
HttpServletRequest对象代表客户端浏览器的请求,当客户端浏览器通过HTTP协议访问服务器时,HTTP请求中的所有信息都会被Tomcat所解析并封装在这个对象中,通过这个对象提供的方法,可以获得客户端请求的所有信息。
1,获取请求行信息
请求方式 | request.getMethod();---用的比较多 |
资源路径URL | request.getRequestURL();{访问项目外的} |
资源路径URI | request.getRequestURI(); |
协议 | request.getScheme(); |
协议版本号 | request.getProtocol() |
get方式的请求信息 | request.getQueryString() |
当前项目部署的名称 | request.getContextPath();---用的比较多 |
返回发出请求的客户机的IP地址 (客户端) | request.getRemoteAddr() |
返回WEB服务器的IP地址 | request.getLocalAddr() |
返回WEB服务器处理Http协议的连接器所监听的端口 | request.getLocalPort() |
2,获取请求头信息
根据请求头中的key获取对应的value。 {不区分大小写} | request.getHeader("headerKey") |
获取请求头中所有的key,该方法返回枚举类型。 | request.getHeaderNames() |
public class Servlet3 extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println(req.getRequestURL());//返回客户端浏览器发出请求时的完整URL。System.out.println(req.getRequestURI());//返回请求行中指定资源部分。System.out.println(req.getRemoteAddr());//返回发出请求的客户机的IP地址。System.out.println(req.getLocalAddr());//返回WEB服务器的IP地址。System.out.println(req.getLocalPort());//返回WEB服务器处理Http协议的连接器所监听的端口。System.out.println("主机名: " + req.getLocalName());System.out.println("客户端PORT: " + req.getRemotePort());System.out.println("当前项目部署名: " + req.getContextPath());System.out.println("协议名:"+req.getScheme());System.out.println("请求方式:"+req.getMethod());// 根据请求头名或者请求头对应的值System.out.println(req.getHeader("Accept"));// 获得全部的请求头名Enumeration<String> headerNames = req.getHeaderNames();while (headerNames.hasMoreElements()){String headername = headerNames.nextElement();System.out.println(headername+":"+req.getHeader(headername));}}
}
3,获取请求体数据
根据key获取指定value | request.getParameter("key") |
获取复选框(checkbox组件)中的值,返回一个String[] | request.getParameterValues("checkboxkey") |
获取请求中所有数据的key,该方法返回一个枚举类型 | request.getParameterNames() |
获取请求中所有的数据并存放到一个Map结构中,该方法返回一个Map,其中key为String类型value为String[]类型。 | request.getParameterMap() |
设置请求编码 | request.setCharacterEncoding("utf-8") |
HTML页面
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body> <!-- 开发form表单注意事项 1form 不是from 2form表单内部不是所有的标签信息都会提交 一些输入信息 input select textarea ... ... 3要提交的标签必须具备name属性 name属性的作用是让后台区分数据 id便于在前端区分数据 4要提交的标签一般都要具备value属性 value属性确定我们要提交的具体的数据 5 get postget方式数据是通过URL携带提交的数据只能是文本提交的数据量不大get方式提交的数据相对不安全post 将数据单独打包放到请求体中提交的数据可以是文本可以是各种文件提交的数据量理论上没有上限post方式提交数据相对安全当一个表单标签readonly只读 也是会提交数据的hidden 隐藏 也是会提交数据disabled 不可用 显示但是不提交 --> <form method="get" action="myServlet"><table style="margin: 0px auto" width="300px" cellpadding="0px" cellspacing="0px" border="1px"><tr><td>用户名</td><td><input type="text" name="username" id="in1" value="12345" disabled ></td></tr><tr><td>密码</td><td><input type="password" name="pwd"></td></tr><tr><td>性别</td><td><input type="radio" name="gender" value="1" checked>男<input type="radio" name="gender" value="0">女</td></tr><tr><td>爱好</td><td><input type="checkbox" name="hobby" value="1">蓝球<input type="checkbox" name="hobby" value="2">足球<input type="checkbox" name="hobby" value="3">羽毛球<input type="checkbox" name="hobby" value="4">乒乓球</td></tr><tr><td>个人简介</td><td><!--文本域 双标签 页面上显示的文字是双标签中的文本 不是value属性文本域提交的数据不是value属性值,是双标签中的文本--><textarea name="introduce" >b</textarea></td></tr><tr><td>籍贯</td><td><!--selectoption没有定义value属性 那么就提交option中间的文字(不推荐)--><select name="provience"><option value="1">a京</option><option value="2">b津</option><option value="3">c冀</option></select></td></tr><tr align="center"><td colspan="2"><input type="submit" value="提交数据"></td></tr></table> </form> </body> </html>
Servlet页面
package com.mashibing.servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Arrays; import java.util.Enumeration; import java.util.Map; import java.util.Set; /*** @Author: Ma HaiYang* @Description: MircoMessage:Mark_7001*/ public class MyServlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// req获取参数// 如果 前端发过来的数据由数据名但是没有值, getParameter返回的是一个空字符串 ""// 获取的参数在提交的数据中名都没有,getParameter返回的是nullString username = req.getParameter("username");System.out.println("username:"+username);System.out.println("password:"+req.getParameter("pwd"));System.out.println("gender:"+req.getParameter("gender"));// hobby=1&hobby=2&hobby=3 想要获得多个同名的参数 getParameterValues 返回的是一个Sting数组String[] hobbies = req.getParameterValues("hobby");System.out.println("hobbies:"+ Arrays.toString(hobbies));// textareaSystem.out.println("introduce:"+req.getParameter("introduce"));// selectSystem.out.println("provience:"+req.getParameter("provience"));System.out.println("___________________________");// 如果不知道参数的名字?// 获取所有的参数名Enumeration<String> pNames = req.getParameterNames();while(pNames.hasMoreElements()){String pname = pNames.nextElement();String[] pValues = req.getParameterValues(pname);System.out.println(pname+":"+Arrays.toString(pValues));}System.out.println("________________________________");Map<String, String[]> pmap = req.getParameterMap();Set<Map.Entry<String, String[]>> entries = pmap.entrySet();for (Map.Entry<String, String[]> entry : entries) {System.out.println(entry.getKey()+":"+Arrays.toString(entry.getValue()));}} }
回顾http请求:
一个http请求可以分为三个部分,分别是请求行,请求头,请求体
- 请求行
- 请求头
- 请求体
get方式 提交的请求数据通过地址栏提交 ,没有请求体
post方式 提交请求数据单独放到请求体中,请求时所携带的数据 (post方式)
- http支持的请求方式
七,HttpServletResponse响应对象
1,响应行
response.setStatus(222,"故意不写200");
2,响应头
(1)设置响应头(setHeader)【解决乱码】
Response.setHeader(“content-type”,”text/html;charset=utf-8”);
response.setContentType("text/html;charset=utf-8");
response.setCharacterEncoding("utf-8");
Response.setHeader(“hello”,”bjsxt”);
Response.setHeader(“hello”,”sxt”);---只会显示一个,覆盖了。
====在service方法中,写完,运行项目。在浏览器中F12查看响应信息就可以了
(2)设置同名的响应头(addHeader)——怎么能不覆盖呢?
Response.addHeader(“hi”,”bjsxt”);
Response.addheader(“hi”,”sxt”);
(3)设置字符型响应
设置响应类型为文本型,内容含有html字符串,是默认的响应类型 | response.setContentType("text/html") |
设置响应类型为文本型,内容是普通文本。 | response.setContentType("text/plain") |
设置响应类型为JSON格式的字符串 | response.setContentType("application/json") |
(4)设置字节型响应
设置响应类型为图片类型,图片类型为jpeg或jpg格式。 | response.setContentType("image/jpeg") |
设置响应类型为图片类型,图片类型为gif格式 | response.setContentType("image/gif") |
(5)设置响应编码
设置服务端为浏览器产生响应的响应编码,服务端会根据此编码将响应内容的字符转换为字节。 | response.setCharacterEncoding("utf-8") |
设置服务端为浏览器产生响应的响应编码,服务端会根据此编码将响应内容的字符转换为字节。同时客户端浏览器会根据此编码方式显示响应内容。 | response.setContentType("text/html;charset=utf-8") |
(6)在响应中添加附加信息(文件下载)
在实现文件下载时,我们需要修改响应头,添加附加信息。
Content-Disposition:attachment
该附加信息表示作为对下载文件的一个标识字段。不会在浏览器中显示而是直接做下载处理。
filename=文件名,
表示指定下载文件的文件名。
package com.mashibing.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/*** @Author: Ma HaiYang* @Description: MircoMessage:Mark_7001*/
public class MyServlet2 extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 设置响应码//resp.setStatus(500);//resp.setStatus(405, "request method not supported");// 设置响应头//resp.setHeader("Date","2022-11-11");// 自定义头// resp.setHeader("aaa", "bbb");// 高速浏览器响应的数据是什么? 浏览器根据此头决定 数据如何应用// 设置MIME类型 json xml 文件下载 ... ...// resp.setHeader("content-type", "text/css");resp.setContentType("text/html");// 专门用于设置Content-Type 响应头resp.getWriter().write("<h1>this is tag h1</h1>");}
}
3,响应主体
response.getWriter().println("设置响应对象!");
回顾http响应:
http响应部分可以分为三部分:响应行,响应头,响应体
1.响应行
响应状态码列表如下
2. 响应头:
3响应实体:
服务器响应回来的内容
HttpServletResponse
HttpServletResponse对象代表服务器的响应。这个对象中封装了响应客户端浏览器的流对象,以及向客户端浏览器响应的响应头、响应数据、响应状态码等信息。
八,乱码问题
1,请求数据乱码
Request.setCharacterEncoding(“utf-8”);
2,响应的数据乱码
Response.setContentType(“text/html;charset=utf-8”);
Response.setCharacterEncoding(“utf-8”);
===以上3行代码,写在Service的分发方法里!
3,jsp页面乱码
<%@ page contentType="text/html;charset=UTF-8" language="java" %>