本文主要是学习Javaweb做的学习笔记,对应张宇鹏老师讲课视频的笔记,另外参考了 刘扬俊的博客(https://blog.csdn.net/qq_19782019/article/details/80292110)。如果需要引用,请引用原始文献。
1.Servlet概念
Servlet是用Java编写的服务器端程序,主要功能是在于交互地浏览和修改数据,生成动态Web内容。狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指实现了这个Servlet接口的类,一般情况下,我们理解为后者。
2.Servlet API
- javax.servlet 其中包含定义servlet和servlet容器之间契约的类和接口。
- javax.servlet.http 其中包含定义HTTP Servlet 和Servlet容器之间的关系。
- javax.servlet.annotation 其中包含标注servlet,Filter,Listener的标注。它还为被标注元件定义元数据。
- javax.servlet.descriptor,其中包含提供程序化登录Web应用程序的配置信息的类型。
3.Servlet的工作原理
- 当用户发来请求时,TomCat服务器调用对应的Servlet,执行service方法,同时会传入一个ServletRequest对象和一个ServletResponse对象。
ServletRequest对象和ServletResponse对象由Tomcat服务器封装好了,不需要我们实现。
ServletRequest对象中封存在此次HTTP请求。ServletResponse对象表示此次请求对应的响应。 - Servlet根据客户端请求生成响应内容并将其传给服务器
- 服务器将响应返回客户端
具体的实现过程:
4.Servle的生命周期
Servlet生命周期是:从第一次调用到服务器关闭的过程。但是web.xml文件中如果配置了load-on-startup,Servlet的生命周期就是 从服务器开启到服务器关闭。
web.xml文件的配置如下代码:
<!--配置Servlet -->
<!--配置servlet类路径 -->
<servlet>
<servlet-name>first</servlet-name>
<servlet-class>com.ouc.servlet.firstServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<!--配置访问方式 -->
<servlet-mapping>
<servlet-name>first</servlet-name>
<url-pattern>/first</url-pattern>
</servlet-mapping>
Servlet生命周期中有两个重要的方法:init()方法和destory()方法。
注意:
init()方法是对Servlet进行初始化的一个方法,在Servlet第一次被请求,加载进行存储时执行。
destory()方法是在Servlet被销毁时执行,也是Tomcat关闭时执行。
代码示例:
public class ServletLife extends HttpServlet {
//初始化方法,在servlet第一次加载内容的时候被调用
@Override
public void init() throws ServletException {
System.out.println("servlet初始化完成");
}
//service方法,真正处理请求的方法
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.getWriter().write("servlet life");
System.out.println("servlet life");
}
@Override
public void destroy() {
System.out.println("我被销毁了...");
}
}
5.Service()、doGet()和doPost()的区别
不管是get请求还是post请求,如果Servlet类中有service方法,优先调用Servic方法。在没有service()方法的情况下,get请求调用doGet()方法,post请求调用doPost()方法。
注意:
如果在覆写service方法中调用了父类的service()方法(super.service(arg0,arg1)),在service方法处理完之后,会再次根据请求方式响应doGet()方法和doPost()方法。因此一般情况下,不覆写service中调用父类的service方法。
6.Request对象
浏览器发起请求到服务器,会遵循Http协议将请求数据发送给服务器。服务器接受到请求数据会使用request对象进行存储,服务器每接受到一个请求,就会创建一个request对象来存储此次的请求数据。
HTTP请求格式:
- 请求行:请求方式、请求的地址和HTTP协议版本。
- 请求头:消息报头,一般是用说明客户端要使用的一些附加信息。存储格式为键值对。
- 空行:位于请求头和请求数据之间,空行是必须的。
- 请求数据:非必须。
因此我们可以通过Request对象分别获得HTTP协议的请求行,请求头和请求体。
获取请求行数据:
- 获取请求方式:String getMethod();
- 获取URL:String getRequestURL();
- 获取URI:String getRequestURI();
- 获取HTTP协议版本:String getScheme();
获取请求头数据:
- String getHeader(String name);
- Enumeration getHeaderNames();
获取请求体数据:
- String getParameter(String name) ;
- Enumeration getParameterNames();
//获取所有用户请求数据的键的枚举集合。
7.Response对象
在使用Request对象获取了请求数据并进行处理之后,处理的结果会通过Response对象显示到浏览器中。
HTTP的响应格式:
- 响应行(状态行):HTTP版本、状态码、状态消息。
- 响应头:消息包头,客户端使用的附加消息。
- 空行:响应头和相应实体之间的,必须存在的。
- 相应实体:服务器返回给浏览器的信息。
因此我们可以通过Response对象提供的方法分别设置响应行,响应头,响应体。
设置响应头:
- setHeader(String name, String value);
- addHeader(String name, String value);
这两种方法,都可以在响应头中添加响应信息:setHeader方法相同键名会被覆盖,addHeader方法相同键名不会被覆盖。
例:设置响应编码格式
resp.setHeader(“content-type”,“text/html;charset=utf-8”); - sendError(int num,String msg);
设置响应状态码
设置响应实体
- PrintWriter getWriter()
获得字符流,通过字符流的write(String s)方法可以将字符串设置到response 缓冲区中,随后Tomcat会将response缓冲区中的内容组装成Http响应返回给浏览器端。
resp.getWriter().write(String s)
在向客户端发送响应时,大多数都是使用该对象向客户端发送HTML。
8.Request乱码问题和Response的乱码问题
Request乱码问题:
产生乱码的原因:在页面中我们一般使用utf-8进行编码,而在service中使用的编码解码方式默认为:ISO-8859-1编码,但此编码并不支持中文。因此会出现中文乱码的问题。
解决方式:
- 万能方式:使用String进行重新编码。
parameter = newString(parameter.getbytes(“iso8859-1”),“utf-8”); - Get请求方式:分两步
第一步:在service方法中使用req.setCharacterEncoding(“UTF-8”);
第二步:在tomcat服务器目录下修改conf文件下找到server.xml文件,打开进行如下配置:
添加属性:useBodyEncodingForURI=“true”
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" useBodyEncodingForURI="true"/>
- Post请求方式:
在service方法中使用req.setCharacterEncoding(“UTF-8”);
Response乱码问题:
解决方式:两种方式
- resp.setContentType(“text/html;charset=utf-8”);
- resp.setHeader(“content-Type”,“text/html;charset=utf-8”);
9.Request请求转发和作用域
Request请求转发:
服务器在接受到浏览器的请求后,仅仅使用一个servlet进行请求处理,会造成不同的Servlet逻辑代码冗余,Servlet职责不明确。可以使用请求转发解决这个问题。
req.getRequestDispatcher("URI").forward(request, response);
return;
参数:
地址:填写相对路径,直接写Servlet的别名即可
注意:
请求转发后,直接用return结束。
请求转发的特点:
- 一次请求;
- 地址栏信息不会发生改变;
Request作用域
使用请求转发后,不同的Servlet之间可以使用Request对象的作用域来进行数据共享。
req.setAttribute("object name", "object value");
req.getAttribute(onject obj);//返回的是一个Obj对象,需要强转
作用域:基于请求转发,一次请求中的所有Servlet共享
10.重定向
我们考虑两种情况:
- 如果当前请求,Servlet不能够处理,应该怎么办呢?比如说,在淘宝购物时,我们选定商品需要付款的时候,淘宝并不能够处理付款信息,而会自动将链接跳转的支付宝平台。
- 如果使用请求转发,造成表单数据重复提交,怎么办呢?比如在网络比较卡的时候,我们会重复刷新,造成数据表单的重复提交。
为了解决上述两种问题,使用重定向
response.sendRedirect("路径");
return;
参数:
本地路径:URI
网络路径:定向资源的URL
重定向的特点:
- 两次请求
- 浏览器地址信息会发上改变
- 避免表单重复提交
使用时机:
- 如果请求中有表单数据,而且数据比较重要,不能重复提交
- 如果请求被Servlet接手后,无法进行处理。
11.Cookie学习
Cookie技术是浏览器端的数据存储技术,解决了不同的请求需要使用相同的请求数据的问题。我们把请求需要共享的请求数据存储在浏览器端。
其特点为:
- 浏览器端的数据存储技术;
- 适合少量的数据;
- 不安全;
- 以键值对的形式存储。
注意:
- 一个Cookie对象只能存储一条数据。
- 默认的Cookie信息存储好之后,每次请求都会附带,除非设置有效路径
Cookie数据存储:
//临时存储,不设置存储时间,默认为一次会话,存储在浏览器中,浏览器关闭即失效
//创建Cookie对象
Cookie c = new Cookie(String name, String value);
//响应Cookie信息给客户端
resp.addCookie(c);
//定时存储,设置存储时间,存储在用户电脑中
//创建Cookie对象
Cookie c = new Cookie(String name, String value);
//设置Cookie的存储时间
c.setMaxAge(3*24*3600);//设置存储时间为3天
//设置有效路径
c.setPath("URI")
//响应Cookie信息给客户端
resp.addCookie(c);
Cookie数据获取:
//获取cookie信息
Cookie[] cks=req.getCookies();
if(cks!=null){//非空判断
//遍历Cookie信息
for(Cookie c:cks){
String name=c.getName();
String value=c.getValue();
}
}
12.Session学习
Request可以解决一次请求内的不同Servlet的数据共享问题。
Session可以解决一个用户的不同请求的数据共享。
原理:
用户第一次向服务器发送请求,服务器接受请求后,调用相应的Servlet进行处理,同时会给用户创建一个session对象,用来存储用户请求处理的相关公共数据,并将该session对象的JSESSIONID使用Cookie技术存储到浏览器中,保证用户的其他请求能够获取到同一个session对象,也保证了不同请求能够获取到
共享的数据。
特点:
- 存储在服务器端
- 服务器进行创建
- 依赖Cookie技术
- 一次会话
- 默认存储时间是30分钟
//创建session对象/获取session对象
HttpSession hs=req.getSession();
//如果请求中拥有session的标识符也就是JSESSIONID,则返回其对应的session对象
//如果请求中没有session的标识符也就是JSESSIONID,则创建新的session对象,并将其JSESSIONID存储到浏览器内存中
//如果session对象是失效了,也会重新创建一个session对象,并将其JSESSIONID存储在浏览器内存中。
//设置session存储时间
hs.setMaxInactiveInterval(int seconds);
//在指定的时间内session对象没有被使用则销毁,如果使用了则重新计时。
//设置session强制失效
hs.invalidate();
//存储和获取数据
//存储:
hs.setAttribute(String name,Object value);
//获取:
hs.getAttribute(String name) //返回的数据类型为Object
//存储的动作和取出的动作发生在不同的请求中,但是存储要先于取出执行。
使用时机:
一般用户在登陆web项目时会将用户的个人信息存储到Sesion中,供该用户的其他请求使用。
session失效处理:
将用户请求中的JSESSIONID和后台获取到的SESSION对象的JSESSIONID进行比对,如果一致
则session没有失效,如果不一致则证明session失效了。重定向到登录页面,让用户重新登录。
注意:
JSESSIONID存储在了Cookie的临时存储空间中,浏览器关闭即失效。
13.ServletContext对象和ServeletConfig对象
ServletContext对象
Request可以解决一次请求内的不同Servlet的数据共享问题。
Session可以解决同一个用户的不同请求的数据共享。
ServletContext不用用户的数据共享问题。
特点:
- 服务器创建
- 用户共享
- 一个项目只有一个
- 生命周期:服务器启动到服务器关闭
- 作用域:整个项目
使用
- 获取ServletContext对象
//第一种方式:
ServletContext sc=this.getServletContext();
//第二种方式:
ServletContext sc=this.getServletConfig().getServletContext();
//第三种方式:
ServletContext sc=req.getSession().getServletContext();
- 整个项目内数据共享
//数据存储
sc.setAttribute(String name, Object value);
//数据获取
sc.getAttribute("str");//返回的是Object类型
//注意:不同的用户可以给ServletContext对象进行数据的存取。获取的数据不存在返回null。
- 获取项目中web.xml文件中的全局配置数据
sc.getInitParameter(String name); //根据键的名字返回web.xml中配置的全局数据的值,返回String类型。 如果数据不存在返回null。
sc.getInitParameterNames();//返回键名的枚举
配置方式:
//注意 一组<context-param>标签只能存储一组键值对数据,多组可以声明多个 <context-param>进行存储。
<context-param>
<param-name>name</param-name>
<param-value>zhangsan</param-value>
</context-param>
//作用:将静态数据和代码进行解耦。
- 获取项目webroot下的资源的绝对路径。
String path=sc.getRealPath(String path);
//获取的路径为项目根目录,path参数为项目根目录中的路径
- 获取webroot下的资源的流对象
InputStream is = sc.getResourceAsStream(String path);
//此种方式只能获取项目根目录下的资源流对象,class文件的流对象需要使用类加载器获取。path参数为项目根目录中的路径
ServeletConfig对象
使用ServletConfig对象获取在web.xml中给每个servlet单独配置的数据
//获取ServletConfig对象
ServletConfig sc=this.getServletConfig();
//获取web.xml中的配置数据
String code=sc.getInitParameter("config");
web.xml配置:
<servlet>
<servlet-name>ServletConfigServlet</servlet-name>
<servlet-class>com.ouc.servlet.ServletConfigServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>utf-8</param-value>
</init-param>
</servlet>