Servlet
引言
1、什么是Servlet?
- 两个单词的组合 :服务器代码片段
- server :服务器|服务端
- Applet:代码片段
2、Servlet的作用?
通过 程序 生成动态页面
3、Servlet程序的好处
可以通过程序 动态生成页面 页面实现动态效果后, 可以减少存储资源,人力资源的浪费。
Servlet的实现方式
1、Servlet标准:Servlet 接口,JavaEE规范
(1)servlet接口位于:javax.servlet.Servlet包中。
(2)接口的位置:tomcat/lib/servlet-api.jar包中。
2、Servlet的三种实现方式
- 借助接口Servlet(位于javax.servlet)
class 类名 implements Servlet{}
- 需要实现接口中的5个方法
- 与http协议无关
- 借助抽象类GenericServlet{}
class 类名 extends GeneriServlet{}
- 只需要实现一个service方法
- 但是和http协议无关
- 借助抽象类HttpServlet
class 类名 extends HttpServlet{}
- 需要覆盖service方法,用于接收用户的请求和处理的结果响应给客户端
- 和http协议相关
第一个servlet程序
功能:显示当前系统时间
开发步骤:
1、将servlet-api.jar导入到当前的module中
2、定义Servlet类:继承HttpServlet
public class FirstServlet extends HttpServlet {
@Override
public void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {
Date now = new Date();
//1、设置响应的类型
resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
//2、获取响应的输出流
PrintWriter out = resp.getWriter();
//3、利用响应输出流,将结果响应给客户端
out.println("<html><head><title>first</title></head><body>");
out.println(now);
out.println("</body></html>");
}
}
3、书写配置文件
4、部署module:部署到服务器
5、启动服务器
6、在浏览器上访问
http://ip:端口号/module名/url-pattern
http://localhost:8080/servlet_day1/first
7、注意:处理响应乱码问题
需要在获取响应的输出流前面加上设置响应编码格式
response.setCharacterEncoding("utf-8")
常见异常
404
请求资源无效
(1)url地址栏的地址写错,特别是web应用名和url-pattern
(2)检查控制台是否有异常信息
(3)项目结构可能存在问题
405
service写错了
(1)检查servlet重点service方法是声明是否正确
(2)service方法中,不能调用父类的方法:super.service(参数);删除
500
服务端错误
(1)Java源代码运行过程中出现异常
(2)检查异常堆栈信息确定到错误行
(3)确认web.xml重点<servlet>包名.类名</servlet>是否正确
(4)jdk版本和tomcat版本不一致
运行正常,在浏览器提示下载或是另存为
检查是否设置响应类型的参数
response.setContentType("text/html")
servlet修改后没有编号
servlet代码修改,tomcat需要重启才能生效。
网络资源路径
##
url-pattern访问三方式
1、直接通过浏览器访问
在浏览器的地址栏上输入:
http://ip:端口号/module名/url-pattern
2、通过超链接的形式访问url-pattern资源
<a href="/module名/url-pattern"
<a href="/first_servlet/first">查看当前系统时间</a>
3、通过form表单访问url-pattern
<form action="/module名/url-pattern method="post">
<input type="submit" value="提交">
</form>
接受请求参数及带参发送
1、接收请求参数
String 变量 = request.getParameter("参数名字");
如果是post请求方式,为了防止出现中文乱码,需要在接收请求参数的前面
request.setCharacterEncoding("utf-8");
2、三种带参数的请求方式
(1)以form表单 (带请求参数)
<form action="/web应用名/url-pattern" method="get|post">
<input type="" name="">根据每个input发name获取参数对应value值
</form>
a.第一种请求方式为:post
I.以数据包的形式进行发送参数
II.格式:http://ip:端口号/web应用名/url-pattern
III.解决post请求乱码,只需要在获取请求参数的前面加
request.setCharacterEncoding("utf-8");
b.第二种请求方式为:get
(2) 超连接请求带参数
<a href="/web应用名/url-pattern?参数名1=值&参数名2=值">热点文字</a>
- 超链接请求带参数是一种get请求方式
- 实际开发时:利用超链接请求带参数不会有大量数据,通常有修改或是删除id或者查一个的id
<a href="/servlet_day1/param?id=1">删除</a>
(3) 在地址栏中访问url-pattern时,请求带参数
http://ip:端口号/web应用名/url-pattern?参数名=值1&参数名2=值
Servlet的生命周期
1、servlet的生命周期交由tomcat服务器管理
Servlet程序对应的servlet的生命周期交给tomcat服务器管理,作为开发人员不能私自的创建Servlet程序的对象,由tomcat服务器根据需求完成Servlet对象创建
注意:客户端第一次请求url-pattern资源时,tomcat创建servlet资源对应对象(只创建一个)。
- servlet的生命周期由server tomcat进行管理
声明周期阶段 | 调用的方法 | 调用时机 | 执行次数 |
创建/实例化 | 构造方法 | 第一次请求当前url-pattern | 1次 |
初始化 | init() | 创建对象后接着初始化 | 1次 |
服务/处理 | service() | 有请求即调用 | n次 |
销毁 | destroy() | server停止 | 1次 |
线程问题
- servlet在运行时,tomcat只为该类创建1个对象(servlet为单例设计),并由这个对象负责对所有请求它的client进行处理。当多个client同时请求该servlet时,这个对象就称为多线程环境下的临界资源对象,此时必须保证该临界资源对象的正确性(线程安全)
- 方法一:对临界资源对象操作不安全的代码,使用synchronized(效率低)
- 方法二:尽量避免在servlet中定义成员变量
- Servlet单例设计的优缺点
- 缺点:多线程环境下,数据不安全
- 优点:提高效率,减少频繁的创建对象带来的消耗,同时提高 JVM 内存空间的利用率。
JDBC+Servlet整合
Servlet接收到数据需要去数据库中进行数据对比或是将数据同步到数据库,利用 JDBC 完成数据库的操作,Servlet需要调用JDBC业务层中的业务方法。
2、项目整合思路
(1) 创建新的module->引入 web application
(2) 引入 module中需要jar依赖:创建 lib 文件
a. JDBC技术的jar:JDBC资料中提供(mysql)
b. Servlet技术jar:tomcat--》lib包中,servlet-api.jar
注意:将jar拷贝到 module中lib中,右键 add as libarary
(3) 引入 JDBCUtil相关内容,并测试连接Connection通过
a. com.baizhi.zmj.conf :引入 配置文件
b. com.baizhi.zmj.util:引入 JDBCUtil工具类
c. com.baizhi.zmj.test:测试,先测试 连接
---------------以上为环境搭建,以下为项目相关----------------------
(4) 根据项目需求,利用navicat将表创建
(5) com.baizhi.zmj.sql:将sql文件存储
(6) com.baizhi.zmj.entity:完成表对应实体类
---------------根据 项目的需求进行完成----------------------
(7) com.baizhi.zmj.dao:先接口,再实现,每一个方法都必须测试
(8) com.baizhi.zmj.service:先接口,再实现,每一个方法都必须测试
(9) com.baizhi.zmj.servlet:根据需求完成servlet程序
(10) 完成 web.xml配置文件
(11) 整合路径
(12) 部署module-》tomcat
注意:将 jdbc需要jar需要部署到 tomcat服务上:
左上角File->右键第6项Project Structure->左侧Artifacts->
在右侧找到对应的 moudule将需要Lib中jar直接双击即可
(13) 启动tomcat服务器
(14) 浏览器地址输入url
跳转
引入
一个Servlet中完成两块功能:
- 一块功能接受客户端请求参数实现对应业务
- 一块通过响应将结果相应给客户端,没有做到各司其职,不便于后期代码维护。
解决方案:将一个Servlet拆分成两个Servlet,其中一个Servlet负责业务逻辑,另一个Servlet负责给用户展示结果。
两个Servlet开发步骤
(1)逻辑Servlet,通常命名为:XxxAction
--1. 接收客户端请求参数
--2.调用 JDBC 中 service 层业务方法,实现对应的业务
--3.根据结果展示给用户(跳转到对应的XxxView上)
(2)展示Servlet,通常常类命名为:XxxView
--1.设置响应类型
--2.获取响应输出流
--3.利用响应输出流将结果展示给客户端
forward跳转(请求转发)
注意:请求和 Java代码是两条线。。
RequestDispatcher rd = req.getRequestDispatcher("/资源url-pattern");
rd.forward(req,resp);
注意:forward跳转前后,为同一个request(同一个客户端请求)
数据传递
request对象可以作为一个存储空间(作用域)使用,数据以键值对的形式存入存储空间。
request是一个作用域,用于存储命名属性。
request中添加命名属性:request.setAttribute("命名属性名字",obj);
request中获取命名属性:Object obj = request.getAttribute("命名属性");
注意:在 XxxAction中获取的业务结果,需要在XxxView中进行展示的时候,利用request设置命名属性
重定向
- 重定向连接到两个servlet分属于两个请求
- 地址栏发生改变
- 语法
response.sendRediract("/web应用名/url-pattern");
- 两种跳转的区别
1. 登录成功 到 查所有action: 重定向
失败 到 登录页: 重定向
- 添加成功 到 查所有 action: 重定向
失败 到 添加页 : 重定向 - 删除成功 到 查所有 action: 重定向
- 修改成功 到 查所有 action: 重定向
- action中出现异常跳转到error.html:看需求是否有利用request传递数据的需求,有fordward,没有…
- 查所有action跳转到查所有view:fordward
- 查一个action跳转到查一个view:fordward
## 会话跟踪技术
http协议:短连接 无状态
(1) 超文本传输协议,在www网中数据通信必须遵循的规范
(2) 无状态的协议
会话跟踪技术
Cookie:客户端存储用户状态数据的一种手段
HttpSession:服务器存储用户状态数据的一种手段。和request一样,是一种作用域。
(1) 记录客户端浏览器过程数据
(2) 常见会话跟踪技术
a. Cookie[了解]
b. session【重点】
c. URL重写技术
(3) 常见的现象:浏览记录、免登陆、购物车(简易)
Cookie
(1) Cookie由服务端(server)往客户端(client)写的一段小文本,格式:name=value
(2) 创建Cookie对象:cookie只可以写String。
Cookie c1 = new Cookie("name1","value1");
Cookie c2 = new Cookie("name2","value2");
(3) 往客户端写Cookie:
response.addCookie(c1);
response.addCookie(c2);
(4) 从客户端读取Cookie:
Cookie[] cs = request.getCookies();
遍历 cs数组获取每一个 Cookie 存储 c
for(Cookie c:cs){
String name = c.getName();// 获取Cookie的name
String value = c.getValue();// 获取Cookie的value
}
(5) 设置Cookie有效时间:
a. Cookie的有效时间默认和浏览器绑定,浏览器开着,Cookie存活,浏览器关闭,则Cookie失效
b. 设置Cookie有效时间:
c.setMaxAge(60);// 60s 单位为秒,有效时间从Cookie创建开始计算,就和浏览器是否开关无关了。
注意:设置Cookie有效时间必须在 response.addCookie(c); 前面
(6) 缺点:
a. Cookie可以被客户端禁用
b. Cookie可以被客户端删除
设置Cookie的存活时间
cookie.setMacAge(time) ——time单位是秒
- time为正数:存活时间
- time为0,表示删除当前cookie
- time为负数,当前cookie会从存活到浏览器关闭
根据http协议的规定,程序默认只能读取”同一个包"其他程序写出的cookie,如果需要跨包读取cookie,则需要设置path。
cookie.setPath("url");
session(会话)
- 同一个客户端和同一个web应用(module)建立连接之后的多次请求/响应的过程被称为一个session会话。
注意:同一个客户端简单理解为:同一个电脑上同一个浏览器产品
HttpSession session = request.getSession(true);
参数:
true:代表如果获取session对象时,存在,直接使用;不存在,创建session [建议]
false:代表如果获取session对象时,存在,直接使用;不存在,返回null
特点
session和 client 一 一对应(同一个client是指同一个电脑上同时打开的同类浏览器产品 是同一client)
session的生命周期比request大(session比request存活久)
I. request:一个request和它对应的response回来,request失效
ii. session:经历多次请求/响应
session作用域【寿命】
【开始】同一个客户端(client)第一次遇到 request.getSession(true); tomcat为浏览器创建session对象(懒汉式)。
【结束】
I. 超时:tomcat默认30分钟,从第每次 访问开始计算(中间访问过,时间从新计算)手动设置存活时间:session.setMaxInactiveInterval(); 通常时间短一些,数据安全,内存及时释放。
II. 手动销毁:session.invalidate()方法
注意:如果直接关闭浏览器,session对象不会被销毁
session对应一个浏览器
当客户端请求的程序代码里申请session对象时,tomcat会首先读取浏览器上的cookie,查找JSESSIONID这个cookie。
找到:读取cookie的value,根据value在内存中找到对应的session,给用户使用。
没找到:tomcat创建新的session对象,并将session的编号id以cookie的形式写到浏览器上
session的使用
设置命名属性
往命名属性存储数据:session.setAttribute(“名”,值Object);
从命名属性中取数据:Object obj=session.getAttribute(“名”);// 注意强制类型转换
移除命名属性:session.removeAttribute(“名”);
HttpSession开发实际应用
a. 显示用户登录信息:
I. 在LoginAction利用session设置命名属性,将登陆信息存储在session
HttpSession session = request.getSession(true);
session.setAttribute("user",user);
II. 在 XxxView利用seesion获取命名属性:
HttpSession session = request.getSession(true);
User user = (User)session.getAttribute("user");
b. 强制登陆:让用户必须先登陆,再查看相关信息(为了保护数据安全性)
I.在LoginAction利用session设置命名属性,将登陆信息存储在session
HttpSession session = request.getSession(true);
session.setAttribute("user",user);
II. 在查所有Action、View、查一个Action等添加代码:
HttpSession session = request.getSession(true);
Object obj=session.getAttribute("user");
if(obj == null){
// 强制跳转到登陆界面
response.sendRedirect("/servlet_day2/login.html");
return;
}
c. 安全退出:
第一种方式:将session中命名属性登陆标记清了,但是session存活
session.removeAttribute("user");// 只是将session中命名属性清掉
第二种方式:直接将session销毁
session.invalidate();// 销毁session
ServletContext
理解:tomcat启动时,会读取服务器中每个web应用的配置文件web.xml, 并将读到的内容封装到ServletContext 对象保存在内存。 ServletContext对象 和 web应用 一一对应。
一个module对应一个ServletContext
获取ServletConext
ServletContext application = this.getServletContext();
ServletConext application = session.getServletContext();
ServletContext application = super.getServletContext();
存取命名属性
setAttribute("name",value); Object value = application.getAttribute("name"); application.removeAttribute("name");
特点:寿命长(begin:tomcat启动 end:tomcat关闭)
第一个应用:可以设置全局参数:
(1) web.xml文件中配置: <context-param> <param-name>encoding</param-name> <param-value>GBK</param-value> </context-param> (2) 在使用全局参数的代码中获取请求参数: ServletContext context=super.getServletContext(); String value = context.getInitParameter("encoding"); req.setCharacterEncoding(value);
第二个应用:作为作用域对象,设置命名属性
(1) 作用范围:
开始:tomcat服务器启动,ServletContext创建
结束:tomcat服务器关闭,ServletContext销毁
(2) 设置命名属性:
context.setAttribute("属性名",值);
Object obj=context.getAttribute("属性名");// 使用自身类型,强制类型转换
注意:ServletConext作为作用域存储存储数据,一定慎重选择,所有用户共享数据!!!!
用户登录信息 --》 session
统计网站在线人数--》ServletContext
查询所有信息,传递到view --> request
Servlet三大作用域
作用域:在web程序运行过程中,用来存放数据(命名属性)的存储空间。
当服务器关闭时,如果session还在,服务器会将session相关信息存储在硬盘中,下次启动读取。如果那时session还没过期,还可以使用,存储的数据也还在。
过滤器
过滤器中用于定义附加代码(冗余代码)
- arg1:ServletRequest是HttpServletRequest的父类型,实际运行过程client端发出的是HttpServletRequest,如果使用可以强转。
- args2:ServletResponse是HttpServletResponse的父类型
- args3:过滤器链,当预处理结束时,可以使用这个参数放请求通过,访问后续servlet
- 当请求通过多个过滤器时,过滤按照web.xml中配置的先后的顺序进行过滤。