目录
前言
Java Web,是用Java技术来解决相关web互联网领域的技术总和。web包括:web服务器和web客户端两部分。本章主要讲与servlet相关的内容。
Tomcat 的运行机制
一、Tomcat运行原理分析
1.Tomcat 是运行在 JVM 中的一个进程。它定义为【中间件】,顾名思义,是一个在Java项目与JVM之间的中间容器。
2.Web 项目的本质,是一大堆的资源文件和方法。Web 项目没有入口方法 ( main 方法),,意味着 Web 项目中的方法不会自动运行起来。
3.Web 项目部署进 Tomcat 的 webapp 中的目的是很明确的,那就是希望 Tomcat 去调用写好的方法去为客户端返回需要的资源和数据。
4. Tomcat 可以运行起来,并调用写好的方法。那么,Tomcat 一定有一个 main 方法。
5. 对于Tomcat 而言,它并不知道我们会有什么样的方法,这些都只是在项目被部署进 webapp下后才确定的,由此分析,必然用到了 Java 的反射来实现类的动态加载、实例化、获取方法、调用方法。但是我们部署到 Tomcat 的中的Web项目必须是按照规定好的接口来进行编写,以便进行调用
6.Tomcat 如何确定调用什么方法呢。这取决于客户端的请求,http://127.0.0.1:8080/JayKing.Tomcat.Study/index.java?show 这样的一个请求,通过 http 协议,在浏览器发往本机的 8080 端口,携带的参数 show 方法,包含此方法的路径为 JayKing.Tomcat.Study,文件名为:index.java。
http协议
- http协议
- 通信方式
- 建立连接
- 发送请求(请求数据包)
- 发送响应(响应数据包)
- 断开连接
- 数据包格式
- 请求数据包
- 响应数据包
- 请求方式
- get 请求参数在url地址后显示;数据量比较小;不安全;不支持文件上传
- get请求:①浏览器地址直接访问。②form的method设置为get
③超链接 ④异步请求时设置为get
- get请求:①浏览器地址直接访问。②form的method设置为get
- post 数据存在消息体中;数据量大;相对安全;支持文件上传
- post请求:①form的method设置为post ②异步请求时设置为post
- put
- get 请求参数在url地址后显示;数据量比较小;不安全;不支持文件上传
- 通信方式
1.servlet介绍
servlet是sun公司指定的一种用于扩展web服务器的功能的组件规范
- web服务器通常只能处理静态的资源(html,css,js…),为了解决动态的处理数据,就需要对web服务器的功能进行扩展,servlet就是用于处理动态数据的组件规范。
- 组件:符合一定规范,完成部分功能的软件模块。例如java中的servlet,jsp都属于组件。这些软件模块需要放在容器中运行。比如Tomcat就属于容器。因此,servlet,jsp都需要放在Tomcat容器中去允许。
- 容器:符合一定规范,能够运行组件的一种软件。比如:Tomcat,jetty,Jboss…
- Servlet规范:使用servlet的时候,自定义类继承HttpServlet,重新service方法,那么久符合Servlet规范。
Servlet 常称为服务器端小程序,即运行在服务器端的程序,用于处理及响应客户的请求。
Servlet类 是个特殊的java类,继承于HttpServlet。
2.Servlet的开发步骤
- 新建的工程是一个java web项目(maven中的web app)
- Servlet类,基础HttpServlet
- 重写service方法
- service(HttpServletRequest request , HttpServletResponse response)
- request 请求
- response 响应
- java web工程中的web.xml文件
- web.xml文件名不能修改。(tomcat容器找web.xml文件)
- 将java类和浏览器访问的地址做一个映射(mapping)
- 浏览器没办法直接访问java类中的方法,所以需要对java类映射为一个浏览器能访问的url地址。
- 打包(辅助完成)
- 把web项目运行所需要的文件按指定的文件结构保存
- 部署(在idea中可以完成)
- 把打包好的web程序放到Tomcat的过程,就称为部署
- 启动容器
- 容器启动后,可通过浏览器,访问这个java web 项目了。
3.servlet的简单实例
3.1导入jar包
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
3.2servlet的配置
package action;
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.io.PrintWriter;
public class HelloServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
//1.设置编码方式
response.setContentType("text/html;charset=utf-8");//相应格式为html,编码采用utf-8
request.setCharacterEncoding("utf-8");
//2.获取请求参数(http://localhost:8080/web01_war/hello?name=alice)
// url ? 参数
String user = request.getParameter("name");//根据参数的值key,获取参数value
//3.处理数据
String word = user + ",你好";
//4.响应结果
PrintWriter writer =response.getWriter();//获取输出流
writer.println("***********");
writer.println(word);
writer.println("***********");
}
}
3.3web.xml中对servlet配置
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>action.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<!-- 引用存在的servlet-name的名字 -->
<servlet-name>hello</servlet-name>
<!-- servlet映射了一个url地址。
①浏览器地址栏输入地址
②form表单的action属性中,可以使用url地址。
③超链接a标签的href属性中,可以使用url地址。
④ajax - 异步请求中使用 -->
<url-pattern>/hello</url-pattern>
</servlet-mapping>
3.4运行tomcat容器
于浏览器的url即地址栏中输入localhost:8080/web01_war/hello?name=alice
3.5访问方式
//html页面让用户输入数据,表单提交的时候访问servlet
public class BMIServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//1.设置编码
resp.setContentType("text/html;charset=utf-8");
req.setCharacterEncoding("utf-8");
//2.获取参数 -- url http://localhost:8080/bmi?tz=60&sg=1.7
// ? key=value & key1+value1 ,& 用于风隔参数
String tz = req.getParameter("tz");
String sg = req.getParameter("sg");
//3.处理数据
double tz1 = Double.valueOf(tz);
double sg1 = Double.valueOf(sg);
double bmi = tz1 / (sg1 * sg1);
//4.相应结果
PrintWriter writer = resp.getWriter();
String str = "";
if (bmi<18){
str="太瘦了";
}else if(bmi<24){
str="标准身材";
}else if (bmi<28){
str="太胖了";
}else {
str="肥胖状态";
}
writer.println("你的bmi是:"+bmi+"\n");
writer.println("<b style = 'color:red'>"+str+ "</b>");
}
}
<!--
<servlet>
用来声明一个servlet的数据,主要有以下子元素:
<servlet-name> 指定servlet的名称
<servlet-class> 指定servlet的类名称
...
<servlet-mapping>
用来定义servlet所对应的URL,包含两个子元素:
<servlet-name>指定servlet的名称
<url-pattern> 指定servlet所对应的URL
-->
<servlet>
<servlet-name>bmi</servlet-name>
<servlet-class>action.BMIServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>bmi</servlet-name>
<url-pattern>/bmi</url-pattern>
</servlet-mapping>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!-- 绝对路径 :/开始的路径就是绝对路径-->
<!-- 相对路径: 不是/开始的路径,就是相对路径,根据当前路径拼接相对路径-->
<label>请输入体重:</label>
<!-- 这里form 的action="bmi" 就是对应之前web.xml中配置的<url-pattern>/bmi</url-pattern>-->
<form action="bmi" method="get">
<input type="text" name="tz">
<br>
<label>请输入身高:</label>
<input type="text" name="sg">
<br>
<input type="submit" value="计算bmi">
</form>
</body>
</html>
接收前端提交的数据
getParameter(key) 的返回值是 String (使用的时候,需要注意数据类型的转换问题。)
响应结果
4.servlet的地址的设置
public class UrlPatternServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.设置编码
resp.setContentType("text/html;charset=utf-8");
req.setCharacterEncoding("utf-8");
//2.获取请求参数
//3.获取请求的url
//--ContextPath :应用程序的访问路径(Application Context)
String contextPath = req.getContextPath();
//--ServletPath:访问servlet的路径(配置的servlet的url)
String servletPath = req.getServletPath();
System.out.println("contextPath:"+contextPath);
System.out.println("servletPath:"+servletPath);
if (servletPath.equals("/add.do")){
System.out.println("add增加业务");
}else if (servletPath.equals("/update.do")){
System.out.println("update修改业务");
}else if(servletPath.equals("/delete.do")){
System.out.println("delete删除业务");
}else if(servletPath.equals("/list.do")){
System.out.println("list查询业务");
}
else {
System.out.println("请求地址错误,不支持此操作");
}
//4.数据处理
//5.响应结果
PrintWriter writer = resp.getWriter();
writer.println("访问路径:"+servletPath);
writer.println("\n 当前被访问的类:UrlPatternServlet");
}
}
<servlet>
<servlet-name>urlp</servlet-name>
<servlet-class>action.UrlPatternServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>urlp</servlet-name>
<!--
测试地址是否符合要求,静态资源是否被拦截。
*** 浏览器发送请求时,Tomcat通过web.xml文件,优先 访问servlet文件,找到servlet类就访问其service方法
如果没有servlet,就找静态资源,如果找不到静态资源,响应404.
*** Tomcat,优先精确匹配,如果没有精确的地址,就模糊匹配,没有模糊匹配,就找静态资源,都找不到返回404.
*** web.xml中配置servlet的url地址的时候,尽量避免特殊后缀名,例如.jps , .html , .css
① / :模糊匹配,除了jsp以外,其他都会被servlet匹配到。<url-pattern>/</url-pattern>
② /* :模糊匹配,所有地址都会被匹配到<url-pattern>/*</url-pattern>
③ *.xx :模糊匹配,以某个固定后缀名结尾的地址,按后缀名匹配。<url-pattern>*.do</url-pattern>
④ /xx :精确地址,<url-pattern>/mm</url-pattern>该访问地址固定为/mm
⑤ /xx.yy :精确地址, <url-pattern>/mm.do</url-pattern>访问地址固定为: /mm.do
⑥ xx :错误
⑦ /*.xx :错误
⑧ xx.yy :错误
-->
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<!-- 全局参数(context) 当前项目中的servlet都可以调用-->
<context-param>
<param-name>count</param-name>
<param-value>1000</param-value>
</context-param>
5.Servlet的生命周期
(1). 创建Servlet实例。
(2). Web容器调用Servlet的init()方法,对Servlet进行初始化。
(3). Servlet初始化后,将一直存在于容器中,用于响应客户端请求,如果客户端发送GET请求,容器调用Servlet的doGet()方法处理并响应请求;如果客户端发送POST请求,容器调用Servlet的doPost()方法处理并响应请求。或者统一使用service()方法处理来响应用户请求。
(4). Web容器决定销毁Servlet时,先调用Servlet的destory()方法,通常在关闭Web应用时销毁Servlet实例。
1.实例化(使用构造方法创建对象)
2.初始化 执行init方法(只执行一次)
3.请求服务 执行service方法
4.销毁方法 执行destroy方法
特别注意:
一个Servlet同一时刻只有一个实例化对象(实例)。
当多个请求发送到同一个Servlet,服务器会为每个请求创建一个新线程来处理。
JSP
1.关于jsp
jsp是sun公司制定的一种用于服务器端的动态页面的技术规范,也是一种组件,依赖于容器(例如tomcat)进行运行。
jsp不需要再web.xml中进行配置,直接通过它的路径和文件名进行访问。
jsp是一种运行在服务器端的页面,它里面可以包含html , 嵌入一些java代码,通过在tomcat容器中经过解析,输出为html页面。
- servlet : 数据的处理和数据的展示(拼html标签)
- servlet + jsp : servlet做数据处理, jsp做数据的展示。
- servlet做数据展示的时候,不方便(编写代码的时候, 维护代码的时候)
- jsp : 让数据的处理和数据的展示进行分离(解耦)
JSP文件后缀名为 .jsp 。
2.jsp的生命周期
jsp的本质就是servlet。
jsp的生命周期从创建到销毁的整个过程,类似于servlet生命周期,区别在于JSP生命周期还包括将JSP文件编译成servlet。
- 编译阶段:
servlet容器编译servlet源文件,生成servlet类
- 初始化阶段:
加载与JSP对应的servlet类,创建其实例,并调用它的初始化方法
- 执行阶段:
调用与JSP对应的servlet实例的服务方法
- 销毁阶段:
调用与JSP对应的servlet实例的销毁方法,然后销毁servlet实例
JSP生命周期代码实例如下所示:(来自:JSP 生命周期 | 菜鸟教程 (runoob.com))
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<html>
<head>
<title>life.jsp</title>
</head>
<body>
<%!
private int initVar=0;
private int serviceVar=0;
private int destroyVar=0;
%>
<%!
public void jspInit(){
initVar++;
System.out.println("jspInit(): JSP被初始化了"+initVar+"次");
}
public void jspDestroy(){
destroyVar++;
System.out.println("jspDestroy(): JSP被销毁了"+destroyVar+"次");
}
%>
<%
serviceVar++;
System.out.println("_jspService(): JSP共响应了"+serviceVar+"次请求");
String content1="初始化次数 : "+initVar;
String content2="响应客户请求次数 : "+serviceVar;
String content3="销毁次数 : "+destroyVar;
%>
<h1>菜鸟教程 JSP 测试实例</h1>
<p><%=content1 %></p>
<p><%=content2 %></p>
<p><%=content3 %></p>
</body>
</html>
<%@ page import="java.util.Date" %>
3. servlet处理数据, jsp展示数据
// servlet中查询数据
List<BookInfo> bookInfos = service.queryAll();
// 把数据bookInfos ,转发到jsp页面,jsp页面显示数据。
// *** 把需要转发到jsp页面上的数据,保存再request对象中.
req.setAttribute("books" , bookInfos); //
setAttribute(String , Object)
// 当前这个请求对应的路径: http://localhost:8080/web04/list.do
RequestDispatcher dispatcher =
req.getRequestDispatcher("./book/show.jsp"); //参数是
转发的路径
dispatcher.forward(req,resp); // 转发- forward
<%@ page import="java.util.List" %>
<%@ page import="entity.BookInfo" %>
<%@ page import="java.util.ArrayList" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>显示书的信息</title>
<style>
td,th{border: 1px solid black ; padding: 5px;}
</style>
</head>
<body>
<table style="border: 1px solid black" cellspacing="0"
cellpadding="0">
<tr>
<th>书的id</th>
<th>书的名字</th>
<th>书的作者</th>
<th>书的价格</th>
<th>出版日期</th>
<th>书的数量</th>
<th>书的类型id</th>
<th>操作</th>
</tr>
<%
// 1. 从request对象中获取数据。
Object books = request.getAttribute("books");
// 2. 转换数据的类型
if(books!=null){
if(books instanceof List){
List<BookInfo> list = (ArrayList<BookInfo>)books;
// 3. 遍历数据
for(BookInfo bi:list){
// 4. 输出数据
%>
<tr>
<th><%=bi.getBookId()%></th>
<th><%=bi.getBookName()%></th>
<th><%=bi.getBookAuthor()%></th>
<th><%=bi.getBookPrice()%></th>
<th><%=bi.getBookDate()%></th>
<th><%=bi.getBookNum()%></th>
<th><%=bi.getTypeId()%></th>
<th>
<a href="toUpdate.do?bookId=
<%=bi.getBookId()%>">修改</a>
<a href="delete.do?bookId=
<%=bi.getBookId()%>">删除</a>
</th>
</tr>
<%
}
}
}
%>
</table>
</body>
</html>
4.转发和重定向
转发和重定向的代码
else if(servletPath.equals("/delete.do")){
String bookId = req.getParameter("bookId");
if(bookId == null){
req.setAttribute("msg" , "只能根据id删除数据。");
RequestDispatcher rd = req.getRequestDispatcher("./book/info.jsp");
rd.forward(req ,resp);
}else{
Boolean aBoolean = service.deleteOne(Integer.valueOf(bookId));
if(aBoolean == false){
req.setAttribute("msg" , "删除失败");
RequestDispatcher rd = req.getRequestDispatcher("./book/info.jsp");
rd.forward(req ,resp);
}else{ // 删除成功,重定向到list.do
// req.getRequestDispatcher("list.do").forward(req,resp);//转发
resp.sendRedirect(req.getContextPath() + "/list.do"); //sendRedirect--重定向
}
}
- 转发:一个请求完成部分功能,希望剩下的功能由另一个请求完成,这种时候使用转发
- 一般使用servlet完成数据处理, 转发数据到jsp页面,实现数据的展示。
- 转发可以通过request对象,把数据转发给另一个请求
- 转发的本质是一个请求,因为request对象不变(可以共享request中的数据)。
-
转发之后,浏览器地址栏显示的是第一个请求的地址。
-
重定向 :某个请求完成之后,希望浏览器自动发起另一个请求,则使用重定向。
-
使用重定向的时候,浏览器消息头中收到一个 302 状态码和 url地址。浏览器根据这个状态码和 url 地址,自动发起请求。
-
重定向是完全不同的两个请求,是两个 request 对象,两个请求的数据无法共享。
-
浏览器地址栏显示的是第二个请求的地址。
-
-
重定向:两次请求,是两个不同的request对象,不能数据共享
-
转发:本质就是一次请求,是同一个request对象,能共享数据。
-
路径的写法:
-
绝对路径的代码:
/路径, 表示绝对路径。 /web04/add.do --- 绝对路径, 属于硬编码。不方便维护。 String appContext = request.getContextPath();// 获取到application context 的路径。 appContext + /add.do --- 绝对路径。 维护更方便。
-
相对路径的代码:
../ 表示推出当前目录,到上层目录,然后拼接路径。 ./ 表示当前目录,直接拼接路径。 可以省略./
-
1.状态管理
状态(数据)管理(数据存储):浏览器和服务器的多次交互作为一个整体,这个过程中有一些需要使用的数据,这些数据(状态)需要保存起来,用于表示某种状态。
- 客户端状态管理:cookie技术,数据保存在浏览器中。
- 服务器端状态管理:session技术,数据保存在服务器的session对象中。
2.cookie
增加一个cookie
//cookie :服务器中可以设置cookie数据,保存在浏览器中。
public class AddCookieServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
//保存一个count=100 在cookie中
Cookie cookie = new Cookie("count",100+"");//创建一个cookie对象
cookie.setMaxAge(180);//设置cookie的最大有效期。
resp.addCookie(cookie);//把cookie添加到浏览器中
Cookie cookie1 = new Cookie("ip","localhost");//有一个默认的有效期。
resp.addCookie(cookie1);
resp.getWriter().println(""+cookie.getValue()+",ip:"+cookie1.getName());
}
}
获取cookie,修改cookie
//cookie :每次访问服务器的时候,请求中会把这个服务器域名相关的cookie数据发送到服务器端,
// 服务器端就可以获取到这些cookie数据。
public class GetCookieServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
Cookie[] cookies = req.getCookies();
if (cookies != null){
for(Cookie c : cookies){
//键值对 c.getName():cookie 的key c.getValue():cookie的value
System.out.println(c.getName()+":"+c.getValue());
//修改cookie的数据,重新保存在浏览器中
if (c.getName().equals("count")){
c.setValue(Integer.valueOf(c.getValue())+1+"");
resp.addCookie(c);//修改了浏览器中的cookie
}
}
resp.getWriter().println("cookie的数量:"+cookies.length);
}else{
resp.getWriter().println("没有cookie。");
}
}
}
2.1cookie的使用过程
-
服务器端创建cookie对象,再添加到浏览器中。
Cookie c = new Cookie(key ,value); response.addCookie(c)
-
浏览器保存响应结果中要求你需要add的cookie对象,每个cookie和自己的请求的域名一致。
-
浏览器每次给服务器发送请求的时候,会将对应的域名中保存的cookie数据一起发送到服务器。
-
服务器通过request获取cookie对象的数据,根据cookie 的name ,找到value值,进而使用value。
2.2cookie的有效期
cookie.setMaxAge(秒) --设置cookie的有效期
- 没有调用setMaxAge():表示会话期间有效,浏览器关闭,cookie失效。(默认设置)
- setMaxAge(正数) : 有效期就是当前时间 + 正数的秒数。
- 会话期间: 浏览器第一次访问某个服务器,到浏览器关闭的期间,称为一个会话。
2.3cookie的路径问题
-
子路径下可以找到父路径下的cookie
cookie.setPath(url) -- 创建cookie对象之后,可以修改cookie的路径,然后再添加到浏览器中。 比如: http://localhost:8080/web04/xx/yy/aa.do - 这个路径中添加了一个cookie(count ,"100") http://localhost:8080/web04/xx/bb.do - 这个访问不了count.
2.4cookie的特点
- 用户可以删除cookie
- 用户可以禁止cookie
- 存储小于4k的内容
- cookie的个数不宜超过300个,有上限
- 只能存储字符串
- cookie不安全
3.服务器端的状态管理(session)
把整个对话期间所有请求,看做一个整体,这个过程中如果有数据共享,把数据保存到session对象中。
-
request对象:连接断开就无效了。
-
session对象:会话期间都有效。
-
java
//登录成功,把用户信息,保存在session对象中 HttpSession session = req.getSession();//获取session对象 session.setAttribute("myuser",us);//吧数据设置到session对象中。
-
jsp
<% //session是jsp页面的内置对象,可以直接使用。 Object myuser = session.getAttribute("myuser"); User us = new User();//new 一个User 避免空指针 if (myuser != null && myuser.getClass() == User.class){ us = (User) myuser; } %> <h3><%=us.getUname()%>,欢迎使用图书管理系统。</h3> <hr>
session的使用
-
状态管理
- cookie:客户端状态管理
- session:服务器端状态管理
-
session对象的获取
- session对象的获取,和请求中从浏览器中传输到服务器中的cookie(JSESSIONID)有关系
- 根据JSESSIONID 这个cookie,去查找当前请求对应的session对象。
//根据sessionId获取session对象,如果没有获取到,就创建一个session。 HttpSession session = request.getSession(); HttpSession session = request.getSession(boolean);
-
session中保存数据
session.setAttribute(String, Object);
-
session中获取数据
Object obj = session.getAttribute(String);
-
session中删除数据
session.removeAttribute(String); //根据key,删除数据
-
session默认在会话期间有效
-
session会话超时
-
设置session的有效期
session.setMaxInactiveInterval(秒);
-
没有设置有效期,默认为会话有效期。
-
-
设置session无效
-
一般系统有一个退出功能,可以清空session中保存的数据,使用session的invalidate方法,设置session无效。
session.invalidate();
-
1.Filter
Filter、FilterChain、FilterConfig 介绍 | 菜鸟教程 (runoob.com)
sun公司提供的一种特殊的组件规范,主要用于拦截容器的调用过程。
- 规范: 实现Filter接口(实现doFilter方法)
- 特殊:过滤器不能单独使用,需要和servlet进行配合使用
- 组件:实现软件的某个模块功能,需要在容器中运行
- 容器: 一个特殊的软件,可以运行组件 支持多个Filter ,以在web.xml中的配置的顺序进行过滤。
Filter对Servlet 程序进行拦截处理时,它可以决定是否将请求继续传递给 Servlet 程序,以及对请求和响应消息是否进行修改,容器不再直接调用 Servlet 的 service 方法,而是调用 Filter 的 doFilter 方法,再由 doFilter 方法决定是否去激活 service 方法。
Filter的生命周期
- 实例化 (调用构造函数) – 1次
- 初始化(调用init函数) – 1次
- 就绪(调用doFilter函数) – 任意次
- 销毁(调用destroy函数)-- 1次
2. ServletContext的使用
应用程序执行期间都是同一个ServletContext对象,可以在所有请求中,获取到该对象,操作该对象中的数据。
// servletContext: 容器运行程序期间都有效,可以共享数据。
// 容器停止运行,servletContext就无效了。
ServletContext servletContext = request.getServletContext();
// 获取数据
Object total = servletContext.getAttribute("total");
// 设置数据
servletContext.setAttribute("total" , 1);
servlet中数据可以存储的区域:
- servlet的service方法中的变量
- request对象:可以通过转发的方式,把数据转发到其他的请求中
- session对象:可以让一个用户在会话期间,直接使用session中的数据。
- servletContext对象:可以让所有请求在容器运行期间,直接使用servletContext中的数据。
3.JSP 内置对象(隐式对象)
对象 | 描述 |
---|---|
request | HttpServletRequest 接口的实例 |
response | HttpServletResponse 接口的实例 |
out | JspWriter类的实例,用于把结果输出至网页上 |
session | HttpSession类的实例 |
application | ServletContext类的实例,与应用上下文有关 |
config | ServletConfig类的实例 |
pageContext | PageContext类的实例,提供对JSP页面所有对象以及命名空间的访问 |
page | 类似于Java类中的this关键字 |
Exception | Exception类的对象,代表发生错误的JSP页面中对应的异常对象 |
4. EL表达式
expression language: el表达式
el表达式, 主要用于替换掉 <%=xx %>输出语句 。
语法规则
- ${对象} [<%=xx %>]
- ${对象.属性名} [<%=xx.getXXX() %>]
- 对象符合java bean的规范(描述类的属性私有化,提供公开的get/set方法。
- 比如 属性名叫abc , 对应的方法叫getAbc / setAbc)
- ${对象.属性名} ,这里的本质是调用属性名对应的get方法。
- 对象符合java bean的规范(描述类的属性私有化,提供公开的get/set方法。
el表达式的查找数据方式
- 从pageContext, request, session , application等对象中,查找需要输出的对象
- pageContext, request, session , application如果出现了同名的key , 那么查找按小范围优选的原则查找
- 可以通过pageScope, requestScope , sessionScope, applicationScope 指定查找范围。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isErrorPage="true" %>
<html>
<head>
<title>jsp的内置对象介绍</title>
<style>
table{border: 1px solid brown}
th,td{border: 1px solid black;padding: 3px}
</style>
</head>
<body>
<table>
<tr><th>内置对象的名字</th><th>作用</th></tr>
<tr><td>out</td><td>在jsp页面上输出内容</td></tr>
<tr><td>pageContext</td><td>存储数据,这个数据只在当前页面使用</td></tr>
<tr><td>request</td><td>请求对应的request对象,获取request中的数据,在jsp页面使用</td></tr>
<tr><td>session</td><td>session对象,服务器端状态管理</td></tr>
<tr><td>application</td><td>存储数据,可以在整个应用程序运行期间使用</td></tr>
<tr><td>response</td><td>响应结果的对象</td></tr>
<tr><td>page</td><td>类似于this</td></tr>
<tr><td>config</td><td>初始化参数,存在config中</td></tr>
<tr><td>exception</td><td>异常对象,需要使用page指令</td></tr>
</table>
<%
//在四个对象中(作用域不同),存储相同的key
//** 可用范围: application > session > request > pageContext
pageContext.setAttribute("computer","pc computer|");
request.setAttribute("computer","request computer|");
session.setAttribute("computer","session computer|");
application.setAttribute("computer","app computer|");
ServletContext servletContext = config.getServletContext();
String key = servletContext.getInitParameter("key");
try{
int i = 0;
int k = 10/i;
}catch (Exception e){
exception = e;
}
%>
<h3><%= exception.getMessage()%></h3>
<h3><%=key%></h3>
<%=pageContext.getAttribute("computer")%>
<%=request.getAttribute("computer")%>
<%=session.getAttribute("computer")%>
<%=application.getAttribute("computer")%>
<hr>
<h4>使用el表达式获取变量值</h4>
<%-- 根据key找value,范围从小开始扩大直到找到为止--%>
${computer} :从最小域开始查找。
<h4>el表达式,指定查找范围</h4>
request : ${requestScope.computer}
session : ${sessionScope.computer}
application : ${applicationScope.computer}
</body>
</html>
el表达式的使用:
<%@ page import="entity.User" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>el表达式的使用</title>
</head>
<body>
<%
User user = new User();
user.setUid(1005);
user.setUname("小红");
user.setUpwd(null);
request.setAttribute("user",user);
%>
<h3>el表达式输出对象的值</h3>
<%-- el表达式本质是去找对应的get方法。
user.getUid() 方法--%>
uId: ${user.uid}
uName: ${user.uname}
uPwd: ${user.upwd}
<hr>
uPwd: <%=user.getUpwd()%>
<h3>条件运算</h3>
${user.uid > 1000}
<h3>数学运算</h3>
${user.uid + 1000}
<h3>逻辑运算</h3>
${user.uid > 1000 || 3>2 }
<h3>empty运算</h3>
${empty user}
</body>
</html>
el表达式的输出结果
- 如果没有这个key , 输出是空字符串
- 如果有这个key,但是key对应的value值是null , 输出的是空字符串
- 其他情况,输出的是key对应的value值。
el表达式使用cookie
${cookie.cookieName.value}<h3>根据 cookie 的名字找 value</h3><h3> jsessionid: ${cookie.JSESSIONID.value} </h3>
el表达式绝对路径的写法
${pageContext.request.contextPath}替换掉: <% = request . getContextPath ()%>
5. jstl: jsp的标签库
jstl标签,用于替换掉jsp页面上的<% java代码%>
jsp页面上,如果有太多的java代码,对于jsp页面的修改维护,不友好。
5.1导入jstl的jar包
<!-- https://mvnrepository.com/artifact/javax.servlet.jsp.jstl/jstl -->
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl-api</artifactId>
<version>1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/taglibs/standard -->
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
5.2:指令的使用
在jsp页面上,使用taglib指令 ,把想用的标签,导入到jsp页面上,让jsp支持标签的使用
- taglib : jsp的导入标签库的指令
- prefix : 前缀, 给标签添加上前缀之后,可以和其他的重名标签进行区分。
- uri: 标签的访问地址
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page import="java.util.List" %>
<%@ page import="entity.BookInfo" %>
<%@ page import="java.util.ArrayList" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>jsp的标签库</title>
</head>
<body>
<%
int age = 19 ;//判断是否是成年人
int sex = 0 ;//0为女生,1为男生,其他提示性别错误
List<BookInfo> bs = new ArrayList<>();
BookInfo b1 = new BookInfo();
b1.setBookName("book1");
b1.setBookNum(20);
bs.add(b1);
BookInfo b2 = new BookInfo();
b2.setBookName("book2");
b2.setBookNum(30);
bs.add(b2);
bs.add(new BookInfo());
bs.add(null);
request.setAttribute("age",age);
request.setAttribute("sex",sex);
request.setAttribute("bs",bs);
%>
<h1>c:if</h1>
<c:if test="${age > 18}">
成年人
</c:if>
<h1>c:choose</h1>
<c:choose>
<c:when test="${sex == 0 }">女生</c:when>
<c:when test="${sex == 1 }">男生</c:when>
<c:otherwise>性别错误</c:otherwise>
</c:choose>
<h3>c:forEach</h3>
<c:forEach items="${bs}" var="book" varStatus="status">
<p>
${status.index + 1},
<c:if test="${!empty book}">
书名:${book.bookName},
数量:${book.bookNum}
</c:if>
</p>
</c:forEach>
</body>
</html>
更多详细内容请参考:JSP 标准标签库(JSTL) | 菜鸟教程 (runoob.com)
6.jsp的include指令
head.jsp
<% @ page contentType = "text/html;charset=UTF-8" language = "java" %><h3 style = "color: green" > xx , 下午好, 欢迎使用本系统! </h3>
其他.jsp文件调用head.jsp
<%@ include file="head.jsp"%>
1.阐述JSP的作用域
- page:代表与一个页面相关的对象和属性。
- request:代表与客户端发出的一个请求相关的对象和属性。一个请求可能跨越多个页面,涉及多个 Web 组件;需要在页面显示的临时数据可以置于此作用域。
- session:代表与某个用户与服务器建立的一次会话相关的对象和属性。跟某个用户相关的数据应该放在用户自己的 session 中。
- application:代表与整个 Web 应用程序相关的对象和属性,它实质上是跨越整个 Web 应用程序,包括多个页面、请求和会话的一个全局作用域。
2.session 和 cookie 有什么区别?
区别:
(1)存储位置不同:session 存储在服务器端;cookie 存储在浏览器端。
(2)安全性不同:cookie 安全性一般,在浏览器存储,可以被伪造和修改。
(3)容量和个数限制:cookie 有容量限制,每个站点下的 cookie 也有个数限制。
(4)存储的多样性:session 可以存储在 Redis 中、数据库中、应用程序中;而 cookie 只能存储在浏览器中
3.创建线程有哪几种方式?区别是什么?
创建线程有3种方式
(1)继承 Thread 重写 run 方法;
(2)实现 Runnable 接口;
(3)实现 Callable 接口。
区别:
Thread 实现Runnable 接口无返回值, Callable 接口有返回值。
Callable 、Runnable 是接口,Thread 是实现类。
4.线程有哪些状态?
线程的状态:
(1)NEW 尚未启动
(2)RUNNABLE 正在执行中
(3)BLOCKED 阻塞的(被同步锁或者IO锁阻塞)
(4)WAITING 永久等待状态
(5)TIMED_WAITING 等待指定的时间重新被唤醒的状态
(6)TERMINATED 执行完成