目录
Servlet基础
了解B/S,C/S架构
B/S的特点:客户端不需要单独的安装,开发相对简单。主要的业务逻辑是在服务端实现的。
C/S架构的特点:客户端需要安装专门的客户端软件
什么是Servlet
服务器就是一台高性能电脑,电脑上安装了提供服务的软件就称为 xxx服务器
servlet是Sun公司制定的一种来扩展web服务器功能的组件。
(在服务器处理http协议的组件)
注: web服务器通常只能处理静态资源的请求(html),
使用:servlet来扩展可以处理动态资源的请求,(访问数据库)
早期的时候是用CGI来扩展web服务器功能,由于它发繁琐,移植性不好,用的越来越少了。
什么是组件?
符合定的规范,实现部分功能,并且需要部署到相应的容器里才能运行的软件模块。
什么是容器?
符合一定的规范, 提供组件的运行环境。
举例:
1. 邮件服务器: 就是在电脑上安装了提供邮件收发服务的软件
2. ftp服务器: 就是在电脑上安装了提供文件上传下载服务的软件
3. 数据库服务器: 在电脑上安装了提供数据增删改查服务的软件(MySQL/Oracle...)
4. web服务器: 就是在电脑上安装了web服务软件(Webserver)
Web服务软件做了那些事儿
1. 负责建立底层的网络连接
2. 负责将客户端请求的文件返回给客户端
3. web服务器又称为web容器, web容器是用来装组件(Servlet),Web服务软件通过解析请求地址找到对应的Servlet作出响应
什么是Servlet
Sun ( Oracle )公司制定的-种用来扩展Web服务器功能的组件规范.
Servlet是用于扩展Web服务软件业务功能的组件,每一种业务都对应一个单独的Servlet
扩展Web服务器功能
- 早期的Web服务器(如Apache Web服务器)只能处理静态资源请求,无法根据请求计算后生成相应的HTML内容
- 在Servlet出现之前可以使用CGI ( Common Gateway Interface通用网关接口)程序扩展Web服务器功能
- CGI是一种规范,可以使用不同的语言来开发,比如Per、C、Java等都可以,但是CGI开发复杂,性能比较差,可移植性不好
组件规范
组件:在软件开发行业,符合一定规范,实现部分功能,并且需要部署到容器当中才能运行的软件模块
容器:符合一定规范 ,提供组件运行环境的一个程序
Servlet组件运行原理
开发一个Servlet
安装Tomcat
- 预备:安装JDK及配置JAVA_ HOME,PATH,CLASSPATH环境变量
- 下载安装文件
- 解压Tomcat
- 启动Tomcat
- 打开终端: cd /home/soft01/apache -tomcat/bin
- 输入命令:sh startup.sh 或sh catalina.sh run启动
- 打开浏览器,输入地址: http://localhost:8080看到"猫"代表成功
- 关闭Tomcat : sh shutdown.sh
- 分别在Linux和Windows操作系统下安装Tomcat
- 成功启动后,通过在浏览器中输入http://localhost:8080地址进行验证
如何在Eclipse中关联Tomcat
1. 下载Tomcat安装文件: 从苍老师文档服务器, 找到常用下载->Java->Tomcat 8.4.45 解压到一个指定的目录(路径中不要有中文,可以在D盘直接创建java文件夹把下载的文件复制过去)
2. eclipse中window->最后一个->Server->Runtime
如果里面有内容删除, 点击add->找到8.5(没有8.5的同学从文档服务器下载新的eclipse,下载完后记得要配置maven) ->点击Browser->找到第一步解压的文件夹->Finish
3. 找到servers面板(如果找不到 window->show View里面找,还是找不到other里面搜),在servers面板中点击超链接添加对应版本的Tomcat, 添加完之后双击修改单选到中间位置(这一步是修改部署工程的路径 作用后面会讲)
4. 在servers里面Tomcat上右键start启动Tomcat,在控制台输出以下内容后,在浏览器中访问localhost:8080 显示出猫说明搞定
Server startup in 580 ms
如何删除关联
1. 在servers面板中删除添加的Tomcat
2. eclipse中window->最后一个->Server->Runtime 找到添加的Tomcat删除
3. 把解压的Tomcat安装文件夹删除,重新解压
开发Servlet的步骤
-
编写一个实现Servlet接或继承HttpServlet的Java类
-
使用javac命令编译源文件为字节码文件
-
将编译完的组件打包
package cn.tedu;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class HelloServlet extends HttpServlet {
protected void service(HttpServletRequest req,
HttpServletResponse resp) throws ServletException, IOException {
System.out.println("HelloServlet");
//设置响应类型
resp.setContentType("text/html;charset=utf-8");
//获取输出对象
PrintWriter pw = resp.getWriter();
//输出数据
pw.print("你好Servlet");
//关闭资源
pw.close();
}
}
创建Web工程
1. 创建maven工程 把jar改war
2. 改错: 在最长的文件名上面右键点击最长的一个, 此过程是创建了web.xml配置文件,该配置文件中保存着请求路径和Servlet的对应关系
3. 让创建的工程和Tomcat关联, 在工程名上右键->Properties->Targeted runtimes 在里面的Tomcat后面打钩 保存关闭即可
4. 创建Servlet, 包名cn.tedu 类名HelloServlet 删除类里面的注释和代码
5. 重写service方法 ,删除方法中的内容,控制台输出HelloServlet
6. 在工程名上面右键Run as->Run on Server
7. 浏览器中访问http://localhost:8080/servlet_1_1/HelloServlet,显示空白,控制台输出HelloServlet说明OK.
常见错误及解决方式
404错误
404数字是什么?
- 是服务器执行完客户端的请求以后,返回给客户端的一个执行结果的状态编码
- 产生的原因: Web服务器(容器)根据请求地址找不到对应资源。
- 如:
- 地址错误(拼写不正确,字母大小写错误)
- web.xml文件中的两个
- 工程没有部署
- Web应用程序部署结构没有遵守Servlet规范
解决方式
- 按照http : // ip:port / appName / url- pattern规则检查请习地址,区分大小写
- 检查web.xml文件中的
- 只有部署以后的工程才能访问
- 检查工程结构是否符合规范
404控制台并且显示ClassNotFound
解决方案: 检查web.xml中的完整类名和创建的类名是否一致,检查请求的路径和配置文件中的路径 是否一致,如果以上全都一致,Clean工程:1. 在eclipse中Project里面找到clean 2. Servers面板中先 停止Tomcat,展开Tomcat 删除当前的工程 或者在Tomcat上右键Clean
容器如何找到service方法
405错误
- 产生的原因: Web服务器(容器)找不到service( )方法处理请求。
如:
- service方法名称写错
- service方法参数类型与标准不一致
- service方法异常、返回值类型与标准不一致
解决方式
- 检查service( )是否存在
- 检查service( )的签名( 方法名, 参数,返回值,异常类型)是否与覆盖的父类中的方法致
500错误
- 产生的原因:程序在运行过程中出错。如:
- Servlet类没有继承HttpServlet或实现Servlet接口
- web.xml文件中的
- service方法中的代码运行时抛出异常
解决方式
- 检查servlet-class中的包名、类名是否正确
- 检查Servlet类是否继承HttpServlet或实现Servlet
- -检查Servlet的service方法中的代码是否运行出错
Servlet 工作原理
Servlet获取请求参数
获取请求参数值的方法
获取提交的1 : 1的Name-Value的方法
--getParameter(name)
获取提交的1 : M的Name- Values的方法
--getParameterValues(name)
getParameter方法
- 常用于传入的参数中,一 个名字对应一个值的形式
- String request.getParameter(String paramName )
- 如果参数名写错,会产生null
getParameterValues方法
- String[ ]request.getParameterValues(String paramName)
- 当需要获取参数名相同的多个参数值时使用该方法
- 多用于获取提交的表单中复选框的值。
- 如果该参数名不存在,则返回null
package cn.tedu;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class SayHelloServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取参数
String info = request.getParameter("info");
//设置响应类型
response.setContentType("text/html;charset=utf-8");
//获取输出对象
PrintWriter pw = response.getWriter();
//输出数据
pw.print(info+"您好!");
//关闭资源
pw.close();
}
}
请求方式
为什么区分请求方式
-
请求方式是客户端对话服务器时的意向说明,是区分请求种类的关键。
-
不同的请求方式不仅仅在数据传输时会有所不同,在表单提交及服务器端处理时都会采用不同的方式,而区分不同种类的请求方式也会使得浏览器采用不同的缓存方式处理后续请求,从而提升响应速度。
客户端发出请求的几种方式
1. 在浏览器的地址栏中写请求路径 回车后发出请求 get
2. 在页面中通过超链接发出请求 get
3. 在页面中通过form表单发出请求 get/post
请求方式的种类
GET请求方式
- 当需要向服务器请求指定的资源时使用的方法
- 它不应该用于一些会造成副作用的操作中 (在网络应用中用它来提交请求是一种常见的错误用法)
- 什么情况浏览器发送Get请求
- 在地址栏输入一个地址
- 点击链接
- 表单默认提交
- 会将请求数据添加到请求资源路径的后面,所以只能提交少量的数据给Web服务器
- 请求参数显示在浏览器地址栏上,不安全
GET: 请求参数放在请求地址的后面,请求参数有大小限制 只能传递几k的数据,而且参数在地址栏中可以看到 所以不能传递敏感信息(密码)
- 浏览器地址栏发出的请求是get
- 超链接发出的请求是get
- form表单默认发出的请求是get
POST请求方式
- 向服务器提交需要处理的数据, 这些数据写在请求的内容里,可以导致新资源的产生和已有资源的更新。
- 什么情况浏览器发送POST请求设置表单method属性为POST
- 请求参数添加到实体内容中,可提交大量数据
- 不会将请求参数显示在浏览器地址栏,相对安全
Post:请求参数放在请求体里面用户看不到,而且没有大小限制 通常上传文件时或者传递敏感信息时使用POST
- 只有form表单设置method="post"时 发出的才是post请求
创建的Servlet需要改名的话,切记把web.xml中的一起改掉不然报错
修改Servlet或页面里面的代码不需要重新运行工程,新增了Servlet后因为web.XML文件修改了 所以需要重新运行工程
处理中文参数
表单提交中文乱码
- 为什么会产生乱码
当表单提交时,浏览器会对中文参数值进行编码(会使用打开表单所在的页面时的字符集进行编码)。Web服务器在默认情况下会使用iso- 8859-1去解码
- 编码与解码方式不一致时就会出现乱码
解决POST方式时的乱码问题
- post请求参数有中文时每次获取参数之前执行以下代码
request.setCharacterEncoding("UTF-8");
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Post方法");
//获取传递过来的参数
//Post 请求获取参数时 如果有中文 必须 每次添加以下代码
request.setCharacterEncoding("UTF-8");
String info =request.getParameter("info");
System.out.println(info);
}
解决GET方式时的乱码问题
get请求获取参数时中文乱码问题
Tomcat8.0以下版本才会有此问题, 找到Servers工程中的server.xml里面的65行 添加以下URIEncoding="UTF-8"属性
<Connector URIEncoding="UTF-8" connectionTimeout="20000"
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Get方法");
//获取传递过来的参数
String info = request.getParameter("info");
System.out.println(info);
}
Servlet输出中文
为什么返回的页面会有乱码
- 编码:将Unicode字符集对应的字节数组转换成某种本地字符集(如UTF-8 )对应的字节数组
- 解码:将某种本地字符集对应的字节数组转换为Unicode字符集对应的字节数组
- 编码和解码使用的字符集不一致就产生 了乱码问题
如何解决输出内容的乱码
- 在获取WriteOut对象及调用out方法之前调用set ontentType方法
- response.setContentType( "text/html;charset-=utf-8" )
- 作用:
- 通知容器,在调用out.println方法输出时,使用指定的字符集
- 生成消息头中content type的值,通知浏览器,服务器返回的数据类型和字符集
Servlet访问数据库
使用JDBC技术访问数据库
- 将JDBC驱动( jar文件)放到WEB INF\ib下。原因是:ClassLoader找到字节码文件,然后加载到VM的方法区中,变成一个对象。Tomcat都有 自己的类加载器,会去WEB-INF下面lib中找字节码文件。因为jar包中都是字节码文件
- 编写JDBC代码,需要注意异常的处理
Servlet运行过程
Servlet运行的详细步骤
- step1、浏览器依据IP建立与容器的连接
- step2、浏览器请求数据打包
- step3、容器解析请求数据包,封装对象
- step4、容器依据路径找到Servlet创建对象
- step5、容器调用Servlet对象的service方法
- step6、容器将响应打包发给浏览器
- step7、浏览器取出结果,生成页面
BMI练习
- BMI身体质量指数 = 体重(kg)/身高(m)的平方 70/(1.8*1.8)
- 18.5以下 体重偏轻 18.5-24之间正常体重 24-28之间偏重 大于28肥胖
- 步骤:
1. 创建bmi.html页面 页面中添加form表单,提交地址BMIServlet,两个文本输入框(name分别为h和w) 和一个提交按钮
2. 创建BMIServlet 留下doGet方法获取传递过来的身高体重,转成double类型按照上面的公式进行计算得到bmi的值,判断bmi的值是在哪个范围来决定给页面返回什么数据
package cn.tedu;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class BMIServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取参数
String hStr = request.getParameter("h");
String wStr = request.getParameter("w");
//把字符串类型转成浮点数
double h = Double.parseDouble(hStr);
double w = Double.parseDouble(wStr);
//计算bmi bmi=体重/身高的平方
double bmi = w/(h*h);
// 18.5 24 28
String info = null;
if(bmi<18.5) {
info = "兄弟你瘦了";
}else if(bmi>=18.5&&bmi<24) {
info = "恭喜你!体重正常 继续保持";
}else if(bmi>=24&&bmi<28) {
info = "哥们儿可以少吃点儿了";
}else {
info = "肥胖!!!!!";
}
//设置响应类型
response.setContentType("text/html;charset=utf-8");
PrintWriter pw = response.getWriter();
pw.print(info+bmi);
pw.close();
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="BMIServlet">
<input type="text" placeholder="请输入身高(m)" name="h" >
<input type="text" name="w" placeholder="请输入体重(kg)">
<input type="submit" value="查询">
</form>
</body>
</html>
路径处理
什么是重定向
服务器向浏览器发送一个302状态码及一个L ocation消息头(该消
息头的值是一个地址 ,称之为重定向地址), 浏览器收到后会立即
向重定向地址发出请求
重定向原理
1.访问AddEmp
2.执行数据插入操作
3.执行结束后使用重定向代码发回一个数据包,里面包括302状态码和一个消息头Location
4.浏览器收到后会立即向服务器的istEmp发出请求
3 ,4过程就是重定向
如何重定向
使用响应对象的AP I方法即可实现重定向的过程,在Servlet中编写如下代码
response . sendRedirect("url");
该段代码使得响应数据包中数据发生如下变化:
HTTP /1.1 302 Moved Temporarily
Server : Apache-Coyote / 1.1
Location : http://localhost : 8080/ appName/url
Content-Type : text/html ; charset = utf-8
Content-Length : 0
Date : Sat, 03 Jan 2013 08:15: 24 GMT
重定向特点
- 重定向的地址可以是任意的地址
- 重定向之后,浏览器地址栏的地址会发生改变
- 重定向过程中涉及到的Web组件并不会共享同一个request和response对象
重定向
- 重定向是服务器告诉客户端往指定的路径再次发出请求的指令
- 执行过程: 当服务器执行重定向方法时会给客户端返回302状态码和一个请求路径,浏览器接收到302后会立即往指定的路径再次发出请求-
response.sendRedirect( request.getContextPath()+"/ListServlet");
处理请求资源路径
什么是请求资源路径
在浏览器地址栏中输入的地址格式如下:
Web服务器对请求地址的处理过程
- 在浏览器地址栏输入http : // ip:port/ appName / xx.html
- 浏览器依据ip , port建立与Servlet容器之间的连接,然后将请求资源路径appName/xx.html发送过去给容器
- 容器依据应用名"/appName" 找到应用所在的文件夹,容器会默认请求的是一个Servlet ,查找web.xml文件中所有的Servlet配置
匹配Servlet规则
精确匹配
- 通过将请求资源路径中的具体资源名称与web.xml文件中的"url-pattern"进行对比,严格匹配相等后找到对应资源并执行
- 如:
- 尽管应用中有abc.htm这个具体的页面,也会去执行该url-pattern对应的Servlet ,而不是返回具体的abc. html页面
通配符匹配
- 使用"*"来匹配0个或多个字符
- 如:
- 代表输入任何不同的ur地址都将匹配成功
- http://ip:port/ appName/ abc.html匹配成功
- http://ip:port/ appName/abc/def/gh也匹配成功
后缀匹配
- 不能使用斜杠开头,使用”*”开头的任意多个字符
- 如:会匹配以".do" 结尾的请求
- http://ip:port/ appName/abc.do匹配成功
- http://ip:port/appName/abc/abc/ abc.do也匹配成功
无匹配
- 如果精确匹配、通配符匹配后缀匹配都没有匹配成功时,容器会查找相应的文件
- 查找到对应文件则返回
- 找不到对应文件返回404
- 注:优先级最高的是精确匹配
Servlet实现多请求
为什么要将多Servlet合并
- 一般情况下, Servlet的主要作用为充当控制器的角色,即接受请求并分发给不同的资源,这时Servlet只要有一个就可以完成分发的过程,所以需要将Servlet合并
- 实现合并的步骤:
- 使用后缀匹配模式修改web.xml文件
- 获取请求资源路径,分析具体请求资源后, 依据分析结果调用不同的分支处理代码
使用后缀匹配模式修改web.xml
- 将配置的多个Servlet节点删除
- 保留一对儿servlet、 servlet mapping
- 修改url-pattern节点的内容为: "* .do"
分析请求资源后分发
- 通过调用request.getRequestURI( )方法获取请求资源路径
- 分析对应资源后分发
Servlet特性
Servlet生命周期
什么是Servlet生命周期
容器如何创建Servlet对象、 如何为Servlet对象分配资源、 如何调用Servlet对象的方法来处理请求、 以及如何销毁Servlet对象的整个过程.
生命周期四阶段
阶段一:实例化。
- 什么是实例化?
- 容器调用Servlet的构造器, 创建一个Servlet对象。
- 什么时候实例化?
- 情形1 ,开始容器里面没有Servlet对象,只有收到请求后才会创建Servlet对象。
- 情形2 ,容器启动之后就立即创建相应的实例。
阶段二:初始化
- 什么是初始化?
- 容器在创建好Servlet对象之后,会立即调用该对象的init方法。
- 一般情况下,我们不用写init方法,因为GenericServlet已经提供了init方法的实现(将容器传递过来的ServletConfig对象保存来下,并且,提供了getServletConfig方法来获得ServletConfig对象)。
- init方法只会执行一次
Servlet的初始化参数配置如下,在web . xm1文件中的<Servlet>标签中
<init-param>
<param- name>company</param- name >
<param-value>北京达内</param-value>
</init- param>
读取Servlet的初始化参数如下,在Servlet中
String V= getInitParameter(" company" )
阶段三:就绪
容器收到请求之后调用Servlet对象的service ( )来处理请求。
阶段四:销毁
- 容器依据自身的算法删除Servlet对象,删除前会调用destroy ( )
- 只会执行一-次
- 可以override destroy方法来实现自己的处理逻辑
- 应用程序卸载时一定会调用destroy方法。
servlet声明周期原理图
Servlet核心结构
Servlet接1
GenericServlet抽象类
HttpServlet抽象类
核心结构图
Servlet接口
- Servlet接口主要包括
- init(ServletConfig config)方法
- destroy方法
- service(ServletRequest req , ServletResponse res)方法
- ServletRequest是HttpServletRequest的父接口
- ServletResponse是HttpServletResponse的父接 1
Servlet核心类
- GenericServlet抽象类实现了servlet接P中的部分方法( init和destroy方法)
- HttpServlet抽象类继承了GenericServlet ,实现了service方法
- 查看GenericServlet中init方法源代码, init方法在service方法调用之前调用。容器会先创建ServletConfig对象 ,然后把config对象传给init。
- init()执行完后,ServletConfig对象消失,所以this.config = config可保存对象引用
- Servlet onfig可以访问Servlet初始化的参数。
ServletContext
什么是Servlet上下文
容器启动之后,会为每一个Web应用创建唯一 的一 个符合ServletContext接[要求的对象,该对象就是servlet.上下文。
特点
- 唯一性(一个Web应用对应个servlet )
- 一直存在(只要容器不关闭,应用没有被卸载删除, servlet.上下文就一 直存在)
如何获得Servlet上下文
方式一
通过GenericServlet提供的getServlet ontext ( )
方式二
通过ServletConfig提供的getServletContext ( )
方式三
通过HttpSession提供的getServletContext ( )
方式四
通过FilterConfig提供的getServletContext ( )
Servlet上下文的作用及特点
作用一
使用setAttribute绑定数据
作用二
使用removeAttribute移除绑定数据
作用三
使用getAttribute获取绑定数据
特点
servlet上下文绑定的数据可以被整个应用上的所有组件共享,并且一直可以访问
Servlet线程安全问题
为什么会有线程安全问题
- 容器收到请求之后,会启动一 个线程来进行相应的处理。
- 默认情况下,容器只会 为每个Servlet创建一个实例
- 如果同时有多个请求访问同一个Servlet,则肯定会有多个线程访问这个Servlet的实例。如果这些线程要修改Servlet实例的某个属性,就有可能发生线程安全问题。
保证Servlet的线程安全
//使用synchronized对代码加锁即可
synchronized( this ){
count ++ ;
try {
}catch(
){
..
}
System . out . println( count);
}
在Servlet使用Thymeleaf
结合servlet中使用
改写Servlet输出
- 我们学习Thymeleaf的目的是能将Servlet获得的信息显示在页面上,所以要结合Servlet使用
- 上一个章节中我们将模板引|擎运行结果输出到了控制台
- 如果将代码运行在Servlet中利用response对象可以将结果响应给浏览器
- 浏览器就会解析结果中的HTML代码,并显示
//Servlet类中doPost或doGet方法中编写代码
TemplateEngine templateEngine=new TemplateEngine();
ClassLoaderTemplateResolver resolver = new ClassLoaderTemplateResolver( );
resolver . setCharacterEncoding("utf-8");
templateEngine . setTemplateResolver(resolver);
Context ctx=new Context();
ctx. setVariable("msg" ,"He1lo World!!!");
//套用模板弓|擎,返回字符串
string result = templateEngine . process(" ../index. html", ctx);
/ /设置响应头
response. setContentType ( "text/htm1 ; charset=utf-8");
/ /获得响应输出流
Printwriter writer = response . getWriter();
//输出页面结果
writer .write( result);
writer . close();
结合Servlet使用注意事项
- 上面示例中的HTML文件存放在了web项目的WEB-INF文件夹下
- 在加载时注意路径上的"../index.html"
Thymeleaf代码封装
package cn.tedu.utils;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.http.HttpServletResponse;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;
public class THUtils {
private static TemplateEngine te;
static {
ClassLoaderTemplateResolver r = new ClassLoaderTemplateResolver();
// 设置字符集
r.setCharacterEncoding("UTF-8");
// 创建模板引擎对象
te = new TemplateEngine();
// 引擎对象和解析关联
te.setTemplateResolver(r);
}
public static void write(String fileName,
Context context,HttpServletResponse response
) throws IOException {
//将模板页面和Context 容器中的数据整合得到一个新的html
String html = te.process(fileName, context);
//把得到的html 返回给浏览器2
response.setContentType("text/html;charset=utf-8");
PrintWriter pw= response.getWriter();
pw.print(html);
pw.close();
}
}
为什么需要封装
- 和之前学习的JDBC类似,Thymeleaf代码实现过程中有大量的代码重复
- 我们通过简单的封装将代码中那些完全重复的代码封装到一个新的类中,方便调用
创建ThymeleafHelper
//创建一个名为ThymeleafHe lper的类代码如下
//Thymeleaf的模板引擎
private static TemplateEngine templateEngine;
static{
//初始化Thymeleaf的模板引擎
templateEngine=new TemplateEngine();
ClassLoaderTemplateResolver resolver = new
ClassLoaderTemplateResolver( );
resolver . setPrefix("../");//设置路径前缀
resolver . setsuffix(" . html");/ /设置路径后缀
resolver . setCharacterEncoding ("utf- 8");
templateEngine . setTemplateResolver( resolver);
}
- 不处理Context对象的方法
public static void ThymeleafWrite(String
path , HttpServletResponse response) throws IOException{
//套用模板引擎,返回字符串
String result = templateEngine . process(path, new Context());
//设置响应头
response . setContent Type ( " text/htm1 ; charset=utf-8");
//获得响应输出流
PrintWriter writer = response . getwriter();
//输出页面结果
writer . write(result);
writer . close();
}
在Servlet中调用
JDao dao = new JDao();
List<JuLeBu> list = dao.findAll();
//用来装显示到页面的数据
Context context = new Context();
context.setVariable("list", list);
//将页面和容器中的数据合并,返回给浏览器
THUtils.write("list.html", context, response);
状态管理
状态管理简介
为什么需要状态管理
- Web应用程序使用HTTP协议通信,而HTTP协议是”无状态”协议即服务器旦响应完客户的请求之后 ,就断开连接 ,而同一个客户的下一次请求将重新建立网络连接
- 服务器应用程序有时是需要判断是否为同一个客户发出的请求,比如客户的多次选购商品。因此,有必要跟踪同一个客户发出的一系列请求。
什么是状态管理
- 将客户端(浏览器)与服务器之间多次交互(一次请求,一次响应)当做一个整体来看待,并且将多次交互所涉及的数据即状态保存下来
- 状态指的是数据
- 管理指的是多次交互时对数据的修改
状态管理的两种常见模式
- 客户端状态管理技术:将状态保存在客户端。代表性的是Cookie技术
- 服务器状态管理技术:将状态保存在服务器端。代表性的是Session技术
Cookie
Cookie
什么是Cookie
- 浏览器向Web服务器发送请求时,服务器会将少量的数据以set-Cookie消息头的方式发送给浏览器,浏览器将这些数据保存下来;
- 当浏览器再次访问服务器时,会将这些数据以Cookie消息头的方式发送给服务器
Cookie的原理
如何创建Cookie
Servlet API为使用Cookie提供了javax.servlet.http.Cookie
name:用于区分不同Cookie的名字
value : Cookie的值
//创建Cookie ,代码如下
//创建Cookie对象
Cookie c = new Cookie(String name ,String value);
//添加Cookie对象
response . addCookie( c ) ;
如何查询Cokie
获取客户端的所有Cookie对象:
Cookie[ ]request .getCookies( );
-注:该方法有可能返回null
获取一个Cookie对象的名称或值:
一String Cookie . getName ( ) ;
一String Cookie . getValue ( ) ;
如何修改Cookie
- step1 ,获取客户端发送的所有Cookie
- step2 ,根据name找到要修改的Cookie
- step3 ,调用Cookie的setValue ( String newValue )方法修改该Cookie的值
- step4,将修改后的Cookie加入到response发送回客户端
同名Cookie会覆盖,以达到修改的目的
Cookie[] Cookies = request . getCookies();
if(Cookies != null ){
for(Cookie C : Cookies){
String name = C. getName( ) ;
if(name . equals(“city"){
C. setValue("ShangHai");
response . addCookie( C );
}
}
}
Cookie的生存时间
- 默认情况下,浏览器会将Cookie保存在内存中,只要浏览器不关闭,Cookie就一直存在
- 如果希望关闭浏览器后Cookie仍在,可以通过设置过期时间
- 一void Cookie.setMaxAge(int seconds);
- 注: seconds单位是秒,精度不是很高
- seconds> 0 :浏览器要保存Cookie的最长时间为设置的参数值,如果超过指定的时间,浏览器会删除这个Cookie。此时Cookie保
- 存在硬盘上
- seconds = 0 :删除Cookie。在修改Cookie的生存时间为0后 ,随着response发送回客户端,替换原有Cookie,因生命周期到了即将该Cookie删除。
- seconds < 0 :缺省值,浏览器会将Cookie保存到内存中
Cookie编码
Cookie只能保存合法的ASCII字符。如果要保存中文,需要将中文转换成合法的ASCII字符,即编码。
Cookie解码
编码后的Cookie为了看到实际的中文,需要还原后再显示
//代码如下 -->与编码时格式保持一致
Cookie[ ] Cookies = request. getCookies( );
if(Cookies != nul1){
Cookie C = Cookies[ 0 ] ;
String value = C. getValue( );
value = URLDecoder . decode(value,"utf-8");
}
Cookie的路径问题
什么是Cookie的路径问题
- 浏览器在访问服务器上的某个地址时,会比较Cookie的路径与该路径是否匹配,只有匹配的Cookie才会发送给服务器
- Cookie的默认路径等于添加这个Cookie的Web组件的路径
- 如: /appName/file/addCookie.do添加了一个Cookie ,则该Cookie的路径等于/appName/file
发送Cookie的条件
- 要访问的地址必须是Cookie的路径或者其子路径时,浏览器才会发送Cookie
- 如:
- Cookie的路径是/appName/file
- 则访问/ appName/file/a.do或/appName/file/b.do时会发送Cookie
- 如果访问/appName/c.do则不会发送Cookie
设置Cookie的路径
使用如下代码段可以设置Cookie的路径
Cookie c = new Cookie( "uname" , "Jack" );
C. setpath("/appName" );
response . addCookie(c);
Cookie的局限性
- Cookie可以被用户禁止
- Cookie会将状态保存在浏览器端,不安全。对于敏感数据,需要加密后再使用Cookie来保存
- Cookie只能保存少量的数据,大约4kb左右
- Cookie的个数:是有限制的
- Cookie只能保存字符串
Session
Session
什么是Session(会话)
浏览器访问Web服务器时,服务器会为每个浏览器在服务器端的内存中分配空间,单独创建一个Session对象 ,该对象有一个Id属性
其值唯一, 一 般称之为SessionId ,并且服务器会将这个SessionId (使用Cookie的方式)发送给浏览器;浏览器再次访问服务器时,会将SessionId发送给服务器,服务器可以依据SessionId找到对应的Session对象
Session 工作原理
获得Session
- HttpSession s = request.getSession(boolean flag);
- HttpSession是个接口,后面返回的是符合接[规范的对象
- 当flag为true时:先查看请求中有没有SessionId,如果没有SessionId ,服务器创建一个Session对象 ;如果有SessionId ,依据SessionId查找对应Session对象,找到则返回,找不到则创建一个新的Session对象,所以flag为true时,一定能得到一个Session对象
- 当flag为false时,没有SessionId及有SessionId但没有找到Session对象,均返回null ;找到则返回
- HttpSession s = request.getSession( );
- 等价于request.getSession(true) ;
- 提供该方法是为了代码书写更方便- -些 ,大部分情况下是不管找没找到都需要返回一个Session对象
使用Session绑定对象
注: getAttribute方法的返回值是Object类型,在去除数据时要对其进行数据类型转换,且必须与我们存入的数据类型一-致
删除Sesssion对象
立即删除Session对象:
Session.invalidate( );
Session验证
- 用户访问需要保护的资源时, 可以使用Session验证的方式来保证其安全性,比如要求登陆后才能访问的资源
- 实现Session验证,遵循以下步骤
- 使用Session.setAttribute ( )先绑定数据
- 使用Session.getAttribute ( )方式来读取绑定值,如果没有,则跳转回登录页面
Session超时
什么是Session超时
- Web服务器会将空闲时间过长的Session对象删除掉,以节省服务器内存空间资源
- Web服务器缺省的超时时间限制:一般是30分钟
修改Session的缺省时间
Cookie与Session
浏览器禁用Cookie的影响
如果浏览器禁用Cookie,Session还能用吗?
答案:不能,但有其他的解决方案,服务器在默认情况下,会使用Cookie的方式将SessionId发送给浏览器,如果用户禁止Cookie ,则SessionId不会被浏览器保存, 此时,服务器可以使用如URL重写这样的方式来发送SessionId
什么是URL重写
浏览器在访问服务器上的某个地址时,不再使用原来的那个地址,而是使用经过改写的地址(即,在原来的地址后面加上了SessionId)
实现URL重写
如果是链接地址和表单提交,使用
response.encodeUR ( String url )生成重写后的URL
如果是重定向,使用
response.encodeRedirectURL (String url) ;生成重写后的URL
Session的优缺点
- 优点
- 安全(将状态保存在服务器端)
- Session能够保存的的数据类型更丰富, Cookie只能保存字符串
- -Session能够保存更多的数据, Cookie大约保存4k
- 缺点
- Session将状态保存在服务器端,占用服务器的内存,如果用户量过大,会严重影响服务器的性能
Servlet中有4大作用域对象
分别是: HttpServletRequest,
HttpSession,
ServletContext.
PageContext,
错题笔记