目录
五,什么是生命周期啊?就是说什么时候有的,以及什么时候没的。
(2)设置同名的响应头(addHeader)——怎么能不覆盖呢?
一,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 {
@Override
protected 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 post get方式数据是通过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> <!-- select option没有定义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 { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // req获取参数 // 如果 前端发过来的数据由数据名但是没有值, getParameter返回的是一个空字符串 "" // 获取的参数在提交的数据中名都没有,getParameter返回的是null String 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)); // textarea System.out.println("introduce:"+req.getParameter("introduce")); // select System.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 {
@Override
protected 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" %>
标签:JavaWeb,req,System,笔记,响应,println,Servlet,请求 From: https://blog.csdn.net/2301_81819439/article/details/144025110