javaweb笔记
带有Servlet的webapp
开发步骤
第一步:在webapps目录下新建一个目录,起名crm(webapp的名字)
第二步:在webapp的根目录下新建目录:WEB-INF
注意:该名称为Servlet的规范规定,必须一致
第三步:在WEB-INF目录下新建classes
注意:这也是Servlet的规范
第四步 在WEB-INF下新建目录:lib
注意:这个不是必须的,用于导入jar包,但位置和名称需要符合规范
第五步在WEB-INF的目录下新建web.xml
web.xml是一个配置文件,,是必须的,描述了Servlet和请求路径之间的对照关系,该文件可以从其他的webapp中拷贝,没有手写的必要
第六步:编写java程序,该程序必须实现Servlet的接口
servlet接口不在JDK中,是Oracle提供的,是javaEE的规范中的一员
tomcat实现了servlet接口
在web.xml路径下注册servlet
向浏览器响应一段HTML代码
1 |
|
在servlet中连接数据库,怎么做?
在Servlet中直接编写java代码即可(JDBC)
如何在集成开发环境中创建servlet程序?
新建一个empty project,并且取名
新建模块
这个模块为普通的javase模块
取名为servlet01
让该模块转变为javaee模块
右键该模块,add Framework support(添加框架支持)
添加javaee规范,选择web-application
选择该框架支持,idea会自动生成符合servlet规范的webapp目录情况
idea生成的web目录即使是webapp的根目录
编写servlet程序
class studentServlet implements Servlet(Servlet爆红,且无法导入包)
在project Sturcture处的Modules–>Dependencies下点击加号,添加依赖
(+号中的library大概率的都是tomcat自带的lib中的jar包,选中此按钮为导入全部tomcat的lib中的jar包,或者可以同样点击+号选择jars or diectories 自行选择导入jar包
在学完maven以后,好像也是可以通过maven的坐标 版本号 score 的定义来导入jar包)
在servlet中编写业务代码(在此时连接数据库)
在WEB-INF的目录下新建子目录lib(名字固定,大小写固定)并且以此链接mysql驱动jar包
(感觉还是可以maven导入,目前还没试过)
在web.xml文件中完成studentServlet类的注册
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15<?xml version="1.0" encoding="UTF-8"?>
<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">
<servlet>
<servlet-name>studentServlet</servlet-name>
<servlet-class>javaweb.servlet.studentServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>studentServlet</servlet-name>
<url-pattern>/servlet/student</url-pattern>
</servlet-mapping>
</web-app>给定一个html页面,在html页面中编写一个超链接,用户点击这个超链接,发送请求,tomcat执行后台的StudentServlet
该文件不能放置在WEB-INF 目录中
student.html文件的内容是
a超链接处添加项目名称,此处为xmm
1
2
3
4
5
6
7
8
9
10
11<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>student page</title>
</head>
<body>
<!--此处项目名使用的为xmm-->
<a href="/xmm/servlet/student">student list</a>
</body>
</html>让idea工具关联Tomcat(即将webapp部署到tomcat之中)
相应步骤在j大学专业课sp课程中开头已经学习过了,不再赘述
在弹出服务器设置参数中大多数不需要改动
在Deployment中部署webapp
Application context为/xmm (xmm是在web,xml中取的项目名)
在浏览器中打开,本次编写的网站为…/xmm/student.html
servlet对象的生命周期
什么是servlet的生命周期
一个servlet对象的出生到死亡的整个过程
servlet对象是由谁来进行维护 的?
servlet对象的创建 ,方法调用,对象的最终销毁1,javaweb程序员都是无权干涉的
servlet的生命周期是由tomcat(web server)全权负责 的
tomcat服务器通常我们又称为:web容器(web container)
由web容器来管理Servlet对象
注意!!我们自己new的Servlet对象只是一个普通的servlet对象,并不受web容器管理
web容器创建的servlet对象都会被放入一个集合中(HashMap)只有放置在容器中的servlet才会受到tomcat管理,自己创建的servlet对象不在该容器之中
默认情况下在服务器启动的时候,servlet对象并不会被实例化(合理的),在用户发送请求之前提前创建出的servlet是明显的浪费。
(可以通过设置空参构造进行确认)
若想实现启动服务器时,就创建servlet对象,可以在web.xml中增加以下标签
1
<load-on-startup>0</load-on--startup>
中间的数字代表的是启动服务器时候创建servlet的顺序,越小优先级越高
用户在发送第一次请求的时候servlet对象被实例化(使用的是无参构造)
Aservlet对象被创建出来之后,tomcat服务器马上调用了Aservlet对象的无参构造
无参数构造方法和init方法只会请求一次
这说明,servlet对象是单实例,但是Servlet类不是单例模式,称为假单例(这是因为Servlet是tomcat创建的,与javaweb程序员无关)
并且每次发出申请,service就会执行一次
servlet的destroy方法只会被tomcat服务器调用一次,然后servlet对象就会被销毁
destroy方法执行的时候,实例对象还在,没有被销毁,当方法结束后servlet对象才会被销毁
Servlet
一般不建议程序员使用servlet不要去使用构造方法,因为可能导致无参构造方法消失,这个操作可能导致Servlet对象无法实例化
通常在init方法中使用初始化
使用适配器
config是tomcat创建出来并且进行传递
ServletConfig
- servletconfig是servlet规范中的一员
servletconfig是一个接口
?是谁去实现了这个接口?
Tomcat服务器实现了ServletConfig接口
一个Servlet对象中就有一个ServletConfig对象,这俩对象是一对一的
ServletConfig对象是Tomcat服务器(WEB服务器)创建的,在Servlet创建的时候同时创建ServletConfig对象
ServletConfig的作用
configuration:配置,ServletConfig对象被翻译为Servlet对象的配置信息对象
ServletConfig对象中包装的信息是web.xml文件中
标签中的配置信息 tomcat解析web.xml文件,将web.xml文件中
标签中的信息自动包装到ServletConfig对象之中 1
2
3
4
5public String getInitParameter(String name);//通过初始化参数的name,获取value
public Enumeration<String> getInitParameterNames();//获取所有初始化的参数的name
public ServletContext getServletContext();//获取ServletContext对象
public String getServletName();
//获取Servlet的名字
学不懂,他妈的
HTTP协议
什么是协议?
协议实际上是某些人或者某些组织提前制定好多的一套规范
协议就是一套规范,就是一套标准,由其他人或者组织进行制定
什么是HTTP协议?
http协议是W3C制定的一种超文本传输协议。
超文本是不仅支持传输普通字符串,
B和S之间相互传输数据需要遵循HTTP协议
什么是解耦合?
B和S之间不相互依赖
HTTP的请求协议(B–>S)
HTTP的请求协议包括4部分
- 请求行
- 请求头
- 空白行
- 请求体
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16GET /servlet05/getServlet?username=jack&userpwd=123 HTTP/1.1 //请求行
//请求头(本身没有这个换行)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Connection: keep-alive
Cookie: Idea-75fd4672=73a4fda9-20c5-4f1a-9192-a68c6d64678a
Host: localhost:8080
Referer: http://localhost:8080/servlet05/index.html
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 Edg/109.0.1518.55
//...`
怎么发送GET和POST请求?
到目前为止,只有一种情况可以发送POST请求:使用form表单,并且form标签中的method属性值为:method=“post”
其他所有情况一律都是get请求:
在浏览器地址栏上直接输入URL,回车,属于get请求。
在浏览器上直接点击超链接,属于get请求。
使用form表单提交数据时,没写method,默认就是get
或者使用form的时候,form标签中method属性值为:method=“get”
GET请求和POST请求怎么选择?
get请求比较适合从服务器端获取数据
post请求比较适合向服务器端传送数据
大部分的form表单提交,都是post方式
敏感信息用post请求
文件上传,一定是post请求
get请求和post请求发送的请求数据格式是统一的,只是位置不同
后端和前端发送请求需要一致
避免405错误,doGet和doPost选择其一进行重写
不建议两种方法全部重写,405错误是有意义的
#一个Servlet类的开发步骤:
编写一个Servlet类,直接对HttpServlet进行继承
重写doGet方法或者重写doPost方法,选择重写谁,由程序员决定
将Servlet类配置到web.xml文件之中
准备前端的页面(form表单),form表单中指定请求的路径即可
怎么选择web欢迎页面?
在web.xml文件下配置以下内容
1
2
3<welcome-file-list>
<welcome-file>Login.html</welcome-file>
</welcome-file-list>Login.html设置为所设置的web欢迎页面
web欢迎页面不需要以/开头
如果所需要设置的web欢迎页面,是文件夹下的则所选取的file是
文件夹名/../../Login.html
依旧不需要以/开头,路径默认在web.app下进行寻找
webapp可以设置多个欢迎页面,靠上的优先级高,找不到的往下面找。
tomcat服务器已经提前配置文件好了index.xml的欢迎页面
即默认选择index.html,index.htm,index.jsp文件
关于WEB-INF目录
在WEB-INF目录下面创建一个文件,
WEB-INF目录下的文件是受到保护
HttpServletRequest接口
是Servlet规范中的一员
该接口 的父接口 是Servletrequest
HttpServletRequest对象是tomcat服务器负责创建的,这个对象中封装了HTTP的请求协议,
- 实际上是用户发送请求的时候,遵循了HTTP协议,将HTTP协议中的信息以及数据全部解析出来,然后tomcat服务器把这些信息封装到HttpServletRequest对象之中,传给了javaweb程序员。
- javaweb程序员面向HttpServletRequest接口编程,调用方法就可以就可以获得请求的信息了
- request和response对象的生命周期?
- request对象和response对象,一个请求对象,一个响应对象,这俩对象只在当前请求 中有效(即是一次请求对应一个request,2次则对应2个)
HTTPServletRequest接口中的常用方法
怎么获取前端浏览器用户提交的数据?
- ```java
Map<String,String[]>getParameterMap()
//这个是获取map
EnumertionggetParameterName()
//这个是获取Map集合中所有的key
String[] getParameterValues(String name)
//这是根据key获取Map集合中的value
String getParameter(Sring name)
//获取value这个一维数组中的第一个元素,因为大多数value数组中只会有一个值,所以这个方法最常用
//以上四个方法,和获取用户提交的数据有关系1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- 前端提交的数据格式:username=abc&userpwd=1234&hobby=s&hobby=d
- 采用Map集合来存储:
```null
Map<String.String>
key存储String
value存储String
但这种方式是不对的
因为如果采用以上的数据结构存储会发现key重复的时候value覆盖,比如hobby=s,然后当下一条数据进入的时候hobby就会变成hobby=d,被覆盖了
key存储String
value存储String[]
即key使用单个,value使用数组进行存储
- ```java
前端表单提交数据的时候,假设提交了数字,其实是以字符串的方式进行提交的,所以服务器端获得一定是一个字符串
应用域对象
ServletContext(Servlet上下文对象)是应用域对象
什么时候会考虑使用该应用域对象?
- 第一:所有用户共享数据
- 第二:这个共享的数据量很小
- 第三:这个共享的数据很少进行修改操作
- 在以上3个条件都满足的时候,使用应用域对象,可以大大提升我们的程序的运行效率。
- 实际上向应用域中绑定数据,就相当于把数据放在了缓存之中。
已经见过的缓存技术?
- 字符串常量池
- 整数型常量池
- 数据库连接池
- 线程池
- 后期还会学习,redis、mongoDB…
ServletContext当中有三个操作域的方法:
1 |
|
请求域对象
请求域只在应用域对象范围小很多
一个请求对象request对象对应一个应用域对象
能不能将AServlet和BServlet?
答案是可以的,使用Servlt当中请求转发机制。
request对象的常用方法
1 |
|
第一步:转发
第二步:调用转发器的forward方法进行跳转
第一步和第二步代码可以链接在一起
- ```java
request.getRequestDispatcher(“/b”).forward(request,response);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- 这样就可以保证A和B的servlet中的request和response对象是同一个对象
- 俩个Servlet怎么共享数据?
- 将数据放在ServletContext应用域中,当然是可以的,但是占用资源过多,是不建议的
- 可以将数据放置在request域中,然后由AServlet转发给B,并且保证A和B在同一次请求当中,这样就可以做到多个Servlet共享同一份数据
- 转发的下一个资源必须是Servlet吗?
- 不一定,只要是TOmcat当中的合法资源,都是可以进行转发的,例如html...
- 转发的时候,路径的写法要注意,转发的路径以/开始,不需要加上项目名.
- request对象容易混淆的俩个方法:
```java
//有传入的username=zhangsan&userpwd=123&sex=1
String getParameter("name");
//之前一定执行过:request.setAttriibute("name",new Object());
这俩方法的区别是
第一个方法从表格表单中获取用户提交的数据
第二个方法是获得请求域中绑定的数据
还有一个常见的方法是
1
2request.getRemoteAddr();
//获取客户端IP地址
- ```java
HttpServletRequest接口的其他方法
1 |
|
莫名其妙上课学会的新方法!!!
1 |
|
使用纯Servlet做一个单表的CRUD操作(OA)
使用纯粹的Servlet完成单表的增删改查
实现步骤
第一步:准备一张数据库表
第二步准备一套HTML页面(项目原型)
- 欢迎页面:index.html
- 列表页面:list.html(以列表页面为核心,展开其他页面)
- 新增页面:add.html
- 修改页面:edit.html
- 详情页面:detail.html
第三步:确定需要哪些功能?
只要这个操作链接了数据库,该操作就叫做功能
查看部门列表
新增部门
查看部门信息
删除部门
跳转到修改页面
修改部门
第四步:在idea中搭建开发环境
创建一个webapp(导入各种奇怪的jar包)
向webapp中添加连接数据库的jar包(mysql驱动)
- 必须在WEB-INF目录下新建lib目录,然后将mysql的驱动jar包拷贝到这个目录下,该目录必须叫做lib(全部小写)
JDBC的工具类(未来会使用mybatis)
第五步:实现查看部门列表功能
实现功能最好从前端一步步往后端写,或者从后端一步步往前端写,切忌想到什么写什么
即写代码的过程最好是程序执行的过程,这样可以尽量避免出现错误
假设从前端开始:
第一:先修改前端超链接,用户从这里开始操作
1
2<a href="/oa/dept/list">查看部门列表</a>
//从项目名开始写第二:编写web.xml文件
1
2
3
4
5
6
7
8
9<servlet>
<servlet-name>list</servlet-name>
<servlet-class>top.xgfm737.oa.DeptListServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>list</servlet-name>
<!--web.xml文件的路径也是/开头,但是不需要加项目名-->
<url-pattern>/dept/list</url-pattern>
</servlet-mapping>第三:编写DeptListServlet类继承HttpServlet类,然后重写doGet方法。
注:因为超链接是get请求(我才知道,我是fw)
第四:在DeptListServlet类的doget方法中连接数据库,查询部门,并且动态的进行输出
第六步:实现详情功能(查看部门详情)
建议从前端往后端一步步进行实现
找到所点击的详情在哪,连接数据库然后执行代码
使用
1
String contextPath=request.getContextPath();
获取根路径
向服务器提交数据的格式:url?name=value&name=value
配置web.xml文件
```xml
detail top.xgfm737.oa.web.action.DeptDetailServlet detail /dept/detail 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
- 编写一个DeptDetailServlet类,重写doget方法
- 获取部门编号等动态输出
- 第七步:删除部门
- 使用js脚本加入到deptListServlet之中
- 再发送相对应的get请求,启动DeptDeleteServlet,然后删除相应数据,在成功后跳转回主界面,如果失败,则跳转至error页面
- 第八步:新增部门
- 在新增部门添加超链接至add.html,并在该页面中通过form表单的post传递数据给DeptAddServlet页面,然后成功实现跳转回到主界面,如果失败则跳转至error页面
注意,第七步第八步建议开始事务步骤,通过回滚事务来避免数据的错误
- 第九步:修改部门
- 在修改页面获取到想要修改的部门的信息,在文本框中输出,然后修改
- 在表单修改后的信息通过post请求发送到DeptModifyServlet处
- 然后在DeptModifyServlet中运行,方法类似增加部门,只是修改sql语句
- 然后成功和失败的跳转
# 重定向和请求分派(转发)
- 代码!
- 转发
```java
request.getRequestDispatcher("/dept/list").forward(request,response);
//转发是一次请求,
//无论转发多少次,显示的都是第一次的Servlet的地址
重定向
1
response.sendTedirect(“oa/dept/list”);
发送两次请求,每次重定向都会重新发送请求
转发是由WEB服务器来控制的,A资源跳转到B资源,这些跳转动作是Tomcat 服务器内部完成的
重定向是由浏览器完成的,具体跳转到哪个资源,是浏览器说了算的
转发和重定向应该如何选择?什么时候使用转发,什么时候使用重定向?
注解
在开发中一般使用注解和web.xml双开发
比如@WebServlet,WebServlet注解中有哪些属性?
- name属性:使用指定的Servlet的名字,等同于<servlet -name>
- urlpatterns属性:用来指定Servlet的映射路径。可以指定多个路径
- loadonstartup属性:用来指定在服务器启动阶段是否加载该Servlet,等用于
JSP
JSP实际上就是一个Servlet,index.jsp访问时候,会自动翻译生成index.jsp.java,该类继承HttpJspBase,而HttpJspBase类继承的是HttpServlet,所以说jsp实际上就是一个Servlet类
而JSP的生命周期与Servlet的生命周期完全相同,没有任何区别。
jsp和Servlet都是单例(假单例)
- JSP第一次访问的时候是比较慢的,因为需要先编译JSP文件
- 执行顺序为:
- jsp文件翻译为java源文件
- java源文件编译生成class字节码文件
- 通过class去创建servlet对象
- 调用servlet中的init方法
- 最后调用servlet对象中的service方法
- JSP是什么
- jsp是java程序
- jsp是JavaServer Page的缩写
- Servlet是JavaEE的13个规范
- 所以JSP也是一套规范
- 对JSP进行错误调试的时候,还是要直接打开JSP文件对应的java文件,检查java代码
JSP基础语法
<%java语句%>
是在方法体中写代码
service方法中编写的代码是有顺序的,是逐行执行的(从上至下进行运作)
<%–JSP的注释,并且不会被翻译到翻译到java源代码之中–%>
<%! 声明 %>
- 可以是全是变量,也可以是静态方法等等
<%=输出在浏览器上的数据%>
- 该语句等同于out.print();
JSP和Servlet的区别
jsp和Serlvet本质是一致的
但是jsp是用于展示数据
Servlet是用于收集数据
使用JSP优化OA
优化list页面
- 使用jsp展示前端页面
在servlet中使用JDBC获取结果集RS
- 编写JavaBean,编写相应的方法
在servlet中将rs存入所编写的JavaBean(Dept)集合(Depts)中
- 使用request.setAttribute(String name,Object obj);存入该集合
然后在servlet中转发到jsp页面
- 在jsp页面中用getAttribute(String name);方法,并且用集合类型接住
然后在jsp中通过while循环输出
优化add
优化!!!
当前的OA存在的问题
任何用户都可以访问,这是不安全的
所以我们要添加一个用户登录
- 步骤1 :数据库中添加一个用户数据表
- 步骤2:实现登录页面
session对象(会话)
什么是会话?
- 从打开浏览器到关闭,生成一次会话
一个用户拥有一个独立的session对象,用cookie进行标记
request<session<application
- session具有超时机制,超过多少时间session没有被访问,那么该session将会被删除
- session对象是存储在服务器端的,一个session包括多个请求。
session的实现原理
在web服务器中有一个session列表,存储相对于的map集合,在map集合中存储的key是sessionID
- 第一次发送请求的时候,服务器会创建一个新的session对象,同时给session对象生成一个id,然后存储到web服务器中。
- 第二次发送请求和在session未销毁的之前发送请求的时候,会将浏览器缓存中的sessionid自动发送给服务器,服务器获取到sessionid,然后在session列表中寻找相对应的session对象
一次会话包涵完整的session对象的生命周期。
session对象的销毁是依靠超时机制和手动销毁的
- 因为tomcat无法知道你是否关闭浏览器(因为HTTP协议是无状态协议)
JSESSIONID=xxxxxxxxxx 是以cookie的形似存储在浏览器之中的,浏览器只要关闭,这个cookie就会关闭,内存就会消失,会话等同消失。
cookie禁用
如果禁用cookie(即服务器拒收cookie),每次访问(发送请求)的时候都会生成一个全新的session和与之对应的cookie,之前的cookie和session都会消失,然后因为会话超时消失。
session默认超时时间为30分钟
如果cookie禁用,session机制还能使用?
可以,需要使用URL重写机制
该机制会严重提高开发者的成本,给开发带来了很大的难度,极大的成本,每个超链接后面都要加上url路径
1
<a>/test/session;jsessionid=XXXXXXXXXXXX</a>
用户登录功能有效化
将用户信息加入到session中
1 |
|
在退出登录的servlet下添加销毁session对象的代码
1 |
|
Cookie
session的实现原理中,每个session对象都关联一个sessionid
JSESSIONID的键值对数据其实就是cookie对象
对于ssesion关联的cookie来说,这个cookie是被保存在浏览器的运行内存中的
只要浏览器不关闭,用户再次发送请求的时候,会自动将运行内存中的cookie发送给服务器
cookie最终保存在浏览器客户端上
- 可以保存在运行内存中(浏览器关闭后cooki就消失了)
- 也可以保存在硬盘文件中(永久保存)
cookie有啥用呢?
- cookie何session机制其实都是为了保存会话的状态
- cookie是将会话的状态保存在浏览器上
如果cookie清除,那么所有的记录也会跟着消失
- 登录前的数据存储在cookie上,而登录后的各种数据存储在数据库中
十天内免登录:
该功能也是需要cookie来进行实现的,并且同时选择十天内免登录,登录成功后,浏览器客户端会保存一个cookie,这个cookie保存快来用户名和密码,并且该cookie是保存在硬盘文件当中的,十天有效,在十天内用户再次访问网站的时候,浏览器自动提交cookie给服务器,然后验证,登录
cookie和session机制都是http协议的机制,并不是Java的机制
java的servlet,对cookie提供了哪些支持?
提供了javax.servlet.http.Cookie
cookie在HTTP协议中是这么规定 :当浏览器发送请求的时候,会自动携带该path下的cookie
cookie的有效时间
cookie。setMaxAge(60*60);设置cookie在一小时后关闭
没有设置有效时间,则默认存储在浏览器的运行内存之中,浏览器关闭则cookie消失
只要cookie的有效时间>0,这个cookie一定会存储到硬盘文件当中
cookie的有效时间为0,表示该cookie被删除,主要用在删除浏览器中的同名cookie
cookie的有效期<0,那么该cookie不会被存储在硬盘文件当中,存储在运行内存当中,和不使用setMaxAge是一个效果
1
2
3
4Cookie cookie = new Cookie("productid","13572468"); //创建cookie
cookie.setMaxAge(60*60); //设置cookie的有效时间(秒)
cookie.setPath(“/servlet13”); //手动设置cookie的path
response.addCookie(cookie); //向浏览器发送cookie
1 |
|
JSP九大内置对象
JSP为了方便使用,在加载时就创建九大内置对象
九大内置对象:request、response、session、application、page、pageContext、out、config、exception
pageContext<request<session<application
以上四个作用域都有:setAttribute,getAttribute,removeAttribute方法
以上四个作用域的使用原则是尽量使用小的域
request对象(请求作用域)
session对象(会话作用域)
application对象(应用作用域)
pageContext对象(页面作用域)
response对象
out对象
page对象(其实就是this,当前的servlet)
config对象
exception对象
JSP四大作用域
四大作用域:pageContext、request、session、application
JSP的指令
指令的作用是指导当前jsp翻译引擎工作
JSP指令
- include指令:包含指令
- taglib指令:引入标签库指令,与JSTL标签库息息相关
- page指令:
指令的使用语法
<%@指令名 属性名=属性值 属性名=属性值 属性名=属性值 ……%>
关于page指令的常用属性
1 |
|
1 |
|
EL表达式
EL表达式的作用
Expression Language(表达式语言)
EL表达式可以替代JSP中的java代码,让JSP文件中的程序看起来更加整洁,美观
JSP代码中夹杂着各种java代码导致JSP文件很混乱(后来通过前后端分离解决)
EL表达式可以算是JSP语法的一部分,EL表达式归属于JSP
EL表达式出现在JSP中主要是:
从某个域中取出数据
四个域
pageContext
session
request
application
将取出的数据转换成字符串
将字符串输出到浏览器
EL表达式十分简便,基本语法格式:
${}
举例:
1
2
3
4
5
6
7
8
9
10<%
request.setAttribute("username","zhangsan");
%>
//该输出语句可以替换为下面的EL表达式
<%=requst.getAttribute("username")%>
//与之等效的EL表达式是这样的
${username}EL表达式的使用
数据需要存储到4大范围之一
然后使用EL表达式获取
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24//首先需要编写User类
<%
User user =new user();
user.setUsername("123");
user.setPassword("123");
user.setAge(123);
session.setAttribute("userObj",user);
%>
//{}中写存储到域对象中的name,并且千万不要使用双引号,这会导致直接输出该字符串
${userObj}
//输出该实体对象的地址
${userObj.name}
//输出user的name:123
//该输出需要有相互对应的get方法
${userObj["name"]}
//这样写与上一个等效
//[]里面如果没有双引号会将其看做变量,如果是带双引号的,则回去userObj的数据中寻找name属性
${abc}
//输出存储到域对象中name为abc的数据
${"abc"}
//输出abc如果四个作用域中有重名的存储数据,根据应用域优先级从小到大取出数据
如果不想逆优先级取出数据可以使用如下代码
1
2
3
4${pageScope.data}
${requestScope.data}
${sessionScope.data}
${applicationScope.data}实际开发时,存储的name尽量不要重复,极容易导致获取的数据出现问题,所以xxxScope都是可以省略的
EL表达式如果从四个域中都找不到name对应的数据,会什么也不显示,这样比较友好
${user[“”]}
这个中间的中括号可以有效的避免user的名字中间带.号的时候,避免识别错误
数据实体对象带点
比如${user.a.abc}
这样是无法取值的
掌握EL表达式,怎么从Map集合中取数据:
掌握EL表达式,从数组中获取数据:
1
2
3
4
5String[] user={....};
request.setAttribute("nameArray",user);
${nameArray[index]}
//并且此处的index不会触发数组索引越界异常,十分高效EL表达式严禁{}中有多个.号,这会导致读不出数据
EL表达式中的pageContext对象是隐式的对象,pageContext
并且request.getContextPath
可以在EL表达式中写pageContext.request.contextPath
关于EL表达式的运算符
算术运算符
+-*/%
关系运算符
== != > >= < <= eq
逻辑运算符
! && || not and or
取值运算符
[] .
empty运算符
算数运算符
+号只能加做为运算符,不能作为字符串拼接
如果是强行加上字符串,会报500错,数字格式化异常
关系运算符
只能出现在el表达式
EL表达式中其他的隐式对象:
- pageContext
- param
- paramValues
- initParam
empty运算符的结果是Boolean类型的
JSTL标签库
什么JSTL标签库?
- Java Standard Tag Lib(java标准标签库)
- JSTL标签库通常和EL表达式一起使用,目的是让JSP中的java代码消失
使用JSTL标签库的步骤
引入JSTL标签库对应的jar包
在idea中如何引入
新建lib目录然后add as lib
一定是要和mysql数据库jar包一样
或者可以使用maven导入
1
2
3
4
5
6
7
8
9
10
11<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>使用tablib指令引入标签库
JSTL提供了很多种标签,你要引入哪个标签需要自己选择,重点掌握核心标签库!
1
2
3
4<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
//prefix= 这里写什么都可以,一般都写c
别的有的用fmt,sql 一般都是首字母这样的进行取名在需要使用标签的位置使用。表面使用的是标签,底层实际上还是java代码
JSTL标签的原理
1
2
3
4
5
6<%@tablib prefix="c" uri="http://java.su.com/jsp/jstl/core"%>
//以上uri后面的路径实际上指向了一个xxxt.tld文件
//tld文件实际上是一个xml配置文件
//在tld文件中描述了标签和java类之间的关系
//在以上核心标签库对应的tld文件是c.tld文件
//存在jar包的META-INF目录下
core举例
- if标签
1
2
3<c:if test="${status==1}">
启动
</c>test中添加if判断,如果test判断为正,输出C标签中的东西
foreach标签
相当于for循环
1
2
3
4
5
6<c:forEach items="${brands}" var ="brand">
${brand.id}<br>
${brand.brandName}<br>
${brand.companyName}<br>
${brand.description}<br>
</c>- items:被遍历的容器
- var:被遍历的临时变量
- begin:开始数
- end:结束数
- step:步长
Filter过滤器
各种servlet都是执行自己的业务这些servlet执行前都要判断用户是否要登录,如果用户登录了,可以继续操作,如果没有登录,需要用户登录,而这步骤很多时候都重复的,显然代码没有得到重复利用
这时候就需要用到过滤器了
我们可以使用过滤器来添加过滤代码,这个过滤代码可以添加到Servlet执行前,或者之后进行过滤。Servlet和Filter实际上也都是java程序
过滤器和用户的请求路径相关,目的也就是提升复用性
目标Servlet是否执行,取决于两个条件:
第一:过滤器是否编写chian.doFilter(request,response);
第二:用户请求路径是否和Servlet的请求路径一致
chain.doFilter(requset,response);这行代码的作用是:
- 执行下一个过滤器,如果下面没有过滤器,那么就执行最终的Servlet
- 注意:Filter的优先级,天生就比Servlet的优先级高
- /a.do对应一个Filter也会对应一个Servlet,那么一定是先执行Filter,再执行Servlet
关于Filter的配置路径:
- /a.do、/b.do、/dept/save 这些配置方式都是精确匹配
- /*匹配所有路径
- *.do 匹配后缀,不需要以/开始
- /dept/* 匹配前缀
在web.xml文件中进行配置的时候,Filter的执行顺序是什么?
- 依靠filter -mapping标签的配置位置,越靠上优先级越高
过滤器的调用顺序,遵循栈数据结构
1 |
|
使用webFilter的时候,filter的执行顺序是什么样的呢?
- 执行顺序是比较Filter的类名
- 比如:FilterA和FilterB,则先执行FilterA
- 比如:Filter1和Filter2,则先执行Filter1
Filter的生命周期
- 和Servlet对象的生命周期一致,唯一的区别就是Filter会在tomcat启动时候实例化
Filter过滤器这里有一个设计模式:
- 责任链设计模式
- 优点可以在程序运行阶段,动态的修改web.xml文件,动态的组合程序的调用程序
在编译阶段已经完全确定了调用关系。
- 如果你想改变他们的调用顺序,必须修改以下java源代码。
- java代码修改,需要重新编译,项目需要重新测试,项目需要重新发布。这是一个繁琐的过程。
- 显然,这种设计违背了:OCP原则。(开闭原则)
- 开闭原则:对扩展开放,对修改关闭。
- 对项目扩展我没有意见,但是你扩展的过程中如果修改了我之前写好的代码,这就是你的不对了。
- 最好要达到的效果是,可以扩展,但是最好别改我之前写好的代码。
责任链设计模式:
- 在程序运行阶段,动态的调整程序的运行顺序,过滤器一般配置在xml中,因为这个能够更好地进行改动
Listener监听器
什么是监听器?
监听器是Servlet规范中的一员。就像Filter一样。Filter也是Servlet规范中的一员。
在Servlet中,所有的监听器接口都是以“Listener”结尾。
监听器有什么用?
监听器实际上是Servlet规范留给我们javaweb程序员的特殊时机。
特殊的时刻如果想执行这段代码,你需要想到使用对应的监听器。
Servlet规范中提供了哪些监听器?
jakarta.servlet包下:
ServletContextListener
ServletContextAttributeListener
ServletRequestListener
ServletRequestAttributeListener
jakarta.servlet.http包下:
HttpSessionListener
HttpSessionAttributeListener
该监听器需要使用@WebListener注解进行标注。
该监听器监听的是什么?是session域中数据的变化。只要数据变化,则执行相应的方法。主要监测点在session域对象上。
HttpSessionBindingListener
该监听器不需要使用@WebListener进行标注。
假设User类实现了该监听器,那么User对象在被放入session的时候触发bind事件,User对象从session中删除的时候,触发unbind事件。
假设Customer类没有实现该监听器,那么Customer对象放入session或者从session删除的时候,不会触发bind和unbind事件。
HttpSessionIdListener
- session的id发生改变的时候,监听器中的唯一一个方法就会被调用。
HttpSessionActivationListener
- 监听session对象的钝化和活化的。
- 钝化:session对象从内存存储到硬盘文件。
- 活化:从硬盘文件把session恢复到内存。
实现一个监听器的步骤:以ServletContextListener接口,并且实现其中的方法
第一步:编写一个类实现ServletContextListener接口,并且实现里面的方法
- ```java
void contextInitialized(ServletContextEvent event)
void contextDestoryed(ServletContextEvent event)1
2
3
4
5
6
7
- 第二步:在web.xml文件中对ServletContextListener进行配置,如下:
- ```xml
<listener>
<listener-class>xgfm737.javaweb.MyServletContextListener</listener-class>
</listener>
- ```java
思考一个业务场景:
编写一个功能,记录该网站实时的在线用户的个数
我们可以通过服务器端有没有分配session对象,因为一个session对象就代表了一个用户,那个就可以通过HttpSessionListener来实时监测用户个数
方法:在user类中增加HttpSessionBindingListener 监听器,监听User实体对象是否创建,并且在重写的监听方法中增加aplication存入取出在线人数的变化,然后在list.jsp中通过EL表达式或者是get,<%=%>输出在线人数