#Servlet
1.概念
2.步骤
3.执行原理
4.生命周期
5.Servlet3.0注解配置
6.Servlet的体系结构
* Servlet----接口
* GenericServlet--抽象类
* HttpServlet--抽象类
* GenericServlet将Servlet接口中其他的方法做了默认空实现,只将service()方法
* 作为抽象,将来定义Servlet类时,可以继承GenericServlet,实现service()方法杰克
* HttpServlet:对http协议的一种封装,简化操作
1.定义类继承HttpServlet
2.复写doGet/doPost方法
#Servlet相关配置
1.urlpattern:Servlet访问路径
* 一个Servlet可以定义多个访问路径:@WebServlet({"/D4",“DD4”})
* 路径的定义规则:
* 1./xxx
* 2./xxx/xxx多层路径,目录结构
* 3.*.do
#HTTP协议
* 概念:Hyper Text Transfer Protocol 超文本传输协议
* 传输协议: 定义了,客户端和服务器端通信时,发送数据的格式
* 特点:
* 基于TCP/IP的高级协议
* 默认端口号:80
* 基于请求/响应模型的:一次请求对应一次响应
* 无状态的:每次请求之间相互独立,不能交互数据
* 历史版本
* 1.0每次请求都建立一次连接
* 1.0复用连接
* 请求消息数据格式
* 请求行
* 请求方式 请求url 请求的协议/版本
* GET /请求内容 HTTP/1.1
* 请求方式
* HTTP协议有7中请求方式,常用的有2中
* GET
* 请求参数在url中
* 请求的url长度是有限制的
* 不安全
* POST
* 请求参数在请求体中
* 请求url长度没有限制
* 相对安全
* 请求头
* 请求头名称:请求头值
* 常见的请求头
* 1.User-Agent:浏览器告诉服务器,我访问你使用的浏览器版本信息
* 可以在服务器端获取头的信息,解决浏览器的兼容性问题
* Referer:
* 告诉服务器当前请求从哪里来?
* 作用:
* 1.防盗链:
* 2.统计:
* Connection:可以被复用
* 请求空行
* 做分隔作用
* 请求体
* 封装POST请求消息的请求参数的
* 响应消息数据方式
* tomcat服务器会根据请求url中的资源路径,创建对应的ServletDemo1的对象
* tomcat服务器,会创建request和response对象,request对象中封装请求消息数据
* tomcat将request和response两个对象传递给service方法,并且调用service方法
* 通过request对象获取请求消息数据,通过response对象设置响应消息数据
* 服务器在给浏览器做出响应之前,会从response对象中拿程序员设置的响应消息数据
1.request对象和response对象的原理
* request和response对象是由服务器创建的
* request对象是来获取请求消息,response对象是来响应消息
2.request对象继承体系结构
servletRequest -----接口
| 继承
HttpservletRequest ---- 接口
| 实现
org.apache.catalina.connector.RequestFacade 类(tomcat)
3.request功能:
1. 获取请求消息数据
1. 获取请求行数据
* GET/DAY/DEMO!?name=张山 Http/1.1
* 方法:
* 获取请求方式:GET
* string getMethod()
* 获取虚拟目录:/DAY
* String getContextPath()
* 获取Servlet路径:/DEMO
* String getServletPath()
* 获取get方式请求参数:
* String getQueryString()
* 获取请求URI
* String getRequestURI()
* StringBuffer getRequsetURL()
* 获取协议及版本:Http/1.1
* String getProtocol()
* 获取客户机的IP地址
* String getRemoteAddr()
2. 获取请求头数据
* 方法:
* String getHeader(String name):通过请求头的名称获取请求头的值
* Enumeration getHeadernames():获取所有的请求头名称
3. 获取请求体数据
1. 只有POST请求方式,才有请求体,在请求体中封装了POST请求的请求参数
2. 步骤:
1. 获取流对象
1. BufferedReader getReader():获取字符输入流,只能操作字符数据
2. ServletInputStream getInputStream():获取字节输入流,可以操作所有类型数据
2. 再从流对象中拿数据
2. 其他功能
1. 获取请求参数通用方式
1. String getParameter(String name):根据参数名称获取参数值
2. String getParameterValues(String name):根据参数名称获取参数值的数组
3. Enumeration getParameterNames():获取所有请求参数名称
4. Map getParameterMap():获取所有参数的map集合
中文乱码问题
* get方式:tomcat已经将get方式乱码问题解决了
* post方式:会乱码
* 解决:在获取参数前,设置request的编码request.setCharacterEncoding("utf-8")
2. 请求转发:一种在服务器内部的资源跳转方式
1. 步骤:
1. 通过request对象获取请求转发器对象:RequestDispatcher getRequestDispatcher(String path)
2. 使用RequestDispatcher对象来进行转发:forward(ServletRequest request,ServletResponse response)
2. 特点
1. 浏览器地址栏路径不发生变化
2. 只能转发到当前服务器内部的资源中
3. 转发是一次请求
3. 共享数据:
1. 域对象:一个有作用范围的对象,可以在范围内共享数据
2. request域:代表一次请求的范围,一般用于请求转发的多个资源共享数据
3. 方法:
1. setAttribute(String name,Object obj):存储数据
2. Object getAttitude(String name):通过键获取值
3. removeAttribute(String name)通过键移除键值对
4. 获取ServietContext:
1. ServletContext getServletContext();
##案例:用户登陆
* 用户登陆案例需求
* 编写login.html登陆页面
* username&password两个输入框
* 使用Druid数据库连接池技术,操作MySQL,day14数据库中user表
* 使用jdbcTemplate技术封装JDBC
* 登陆成功跳转到SuccessServlet展示:登陆成功!用户名,欢迎您
* 登陆失败跳转到FailServlet展示:登陆失败,用户名或密码错误
开发步骤
1. 创建项目,导入HTML页面,配置文件,jar包
2. 创建数据库对象
3. 创建一个包,创建user类
/**
* 用户的实体类
*/
public class User {
private int id;
private String username;
private String password;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
#4.创建一个包,创建类UserDao,提供login方法
/**
* 操作数据库中User表的类
*/
public class UserDao {
//声明JDBCTemplate对象共用
private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
/**
* 登录方法
* @param loginUser 只有用户名和密码
* @return user包含用户全部数据,没有查询到,返回null
*/
public User login(User loginUser){
try {
//1.编写sql
String sql = "select * from user where username = ? and password = ?";
//2.调用query方法
User user = template.queryForObject(sql,
new BeanPropertyRowMapper(User.class),
loginUser.getUsername(), loginUser.getPassword());
return user;
} catch (DataAccessException e) {
e.printStackTrace();//记录日志
return null;
}
}
}
/**
* 用户的实体类
*/
public class User {
private int id;
private String username;
private String password;
private String gender;
public void setHehe(String gender){
this.gender = gender;
}
public String getHehe(){
return gender;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", gender='" + gender + '\'' +
'}';
}
}
**
* JDBC工具类 使用Durid连接池
*/
public class JDBCUtils {
private static DataSource ds ;
static {
try {
//1.加载配置文件
Properties pro = new Properties();
//使用ClassLoader加载配置文件,获取字节输入流
InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties");
pro.load(is);
//2.初始化连接池对象
ds = DruidDataSourceFactory.createDataSource(pro);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取连接池对象
*/
public static DataSource getDataSource(){
return ds;
}
/**
* 获取连接Connection对象
*/
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
}
#登陆的具体逻辑
@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.设置编码
req.setCharacterEncoding("utf-8");
/* //2.获取请求参数
String username = req.getParameter("username");
String password = req.getParameter("password");
//3.封装user对象
User loginUser = new User();
loginUser.setUsername(username);
loginUser.setPassword(password);*/
//2.获取所有请求参数
Map map = req.getParameterMap();
//3.创建User对象
User loginUser = new User();
//3.2使用BeanUtils封装
try {
BeanUtils.populate(loginUser,map);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
//4.调用UserDao的login方法
UserDao dao = new UserDao();
User user = dao.login(loginUser);
//5.判断user
if(user == null){
//登录失败
req.getRequestDispatcher("/failServlet").forward(req,resp);
}else{
//登录成功
//存储数据
req.setAttribute("user",user);
//转发
req.getRequestDispatcher("/successServlet").forward(req,resp);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req,resp);
}
}
##1.Http协议:响应消息
1.请求消息:客户端发送给服务器的数据
* 数据格式
* 请求行
* 请求头
* 请求空行
* 请求体
* Host: home.firefoxchina.cn
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:70.0) Gecko/20100101 Firefox/70.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Cookie: acw_tc=7b39758815729304218548467ec17463db1c21c6a47979ae4af6194eb808fb; Hm_lvt_dd4738b5fb302cb062ef19107df5d2e4=1572930423; Hm_lpvt_dd4738b5fb302cb062ef19107df5d2e4=1572930423
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0
2.响应消息:服务器端发送给客户端的数据
* 数据格式
* 响应行
* 组成:协议/版本 响应的状态码 状态码的描述
* 响应的状态码:服务器告诉客户端浏览器本次请求和响应的一个状态
1. 状态码都是3位数字
2. 分类
1. 1xx:服务器接收客户端消息,但没有接受完成,等待一段时间后,发送1xx多状态码
2. 2xx:成功,代表:200
3. 3xx:重定向。代表:302(重定向)304访问缓存
4. 4xx:客户端错误 代表:404(请求路径没有对应的资源)405:请求方式没有对应的doxxx()方法
5. 5xx:服务器错误
* 代表500:服务器内部出现异常
* attachment;filename=xxx:以附件形式打开响应体。文件下载
* 响应头
* 格式:头名称:值
* 常见的响应头
* Content-Type:服务器告诉客户端本次响应体数据格式以及编码格式
* Content-disposition:服务器告诉客户端以什么格式打开响应体数据
* 值:
* in-line:默认值,在当前页面内打开
* 响应空行
* 响应体
* 发送传输的数据,传输的真实数据
HTTP/1.1 200
Set-Cookie: JSESSIONID=F2F555BE8B43C5EBD2B579236128F855; Path=/day15; HttpOnly
Content-Type: text/html;charset=UTF-8
Content-Length: 96
Date: Tue, 05 Nov 2019 05:17:47 GMT(Cdn Cache Server V2.0)
##2.Response对象
* 功能:设置响应消息
* 设置响应行
* 格式:HTTP/1.1-200 ok
* 设置状态码:setstatus(int sc)
* 设置响应头
* setHeader(string name,String value)
* 设置响应体
* 使用步骤
* 获取输出流
* 字符输出流
* PrintWriter getWriter()
* 字节输出流:ServletOutputStream getOutputStream()
* 使用输出流,将数据输出到客户端浏览器
##3.ServletContent对象
1. 概念:代表整个web应用,可以和程序的容器(服务器)来通信
2. 功能:
1. 获取MIME类型:
1. 在互联网通信的过程中定义的一种文件数据类型
1. 格式:大类型/小类型 text/html image/jpeg
* 获取String getMineType(String file)
2. 域对象:共享数据
1. setAttribute(String name,Object value)
2. getAttribute(String name)
3. removeAttribute(String name)
ServletContent对象范围,所有用户所有请求的数据
3. 获取文件的真实(服务器)路径
1. 方法:String getRealPath(String path)
3. 获取:
1. 可以通过request.getServletContent
2. 通过httpServlet获取
1. getServletContent()
* 案例:
* 完成重定向:简单的重定向 response.sendRedirect();
* 重定向的特点
* 地址栏发生变化
* 重定向可以访问其他站点(服务器)的资源
* 重定向是两次请求,不可以使用request对象来共享数据
* 转发向的特点
* 转发地址栏不变
* 转发只能访问当前服务器下的资源
* 转发是一次请求,可以使用request对象来共享数据
* 路径写法:
* 路径的分类
* 相对路径:通过相对路径不可以确定唯一资源
* 如:./index.html
* 不以/开头,以.开头路径
* 规则:确定访问当前资源和目标资源之间的相对位置关系
* 绝对路径:通过绝对路径可以确定唯一资源
* 如:http://localhost/day15/sda
* 以/开头的路径
* 规则:判断定义的路径是谁用的
* 给客户端浏览器使用:需要加虚拟路径(项目的访问路径)
* 建议虚拟目录动态获取
* 给服务器使用:不需要加虚拟目录
动态获取虚拟目录request.getContentPath();
* 服务器输出字符数据到浏览器
* 步骤:
* 获取字符输出流
* 输出数据
* 乱码问题:编码使用的字符集不一致
* setcontentType();
* 设置该流的编码
* 告诉浏览器响应体使用的编码
* 服务器输出字节数据到浏览器
*获取字符输出流
* 输出数据
* 验证码
##文件下载按钮
文件下载需求
1. 页面显示超链接
2. 点击超链接后弹出下载提示框
3. 完成图片文件下载
分析:
* 超链接指向的资源如果能过被浏览器解析,则在浏览器中展示,如果不能解析,则弹出下载提示框,不能满足需求
* 任何资源都必须弹出下载提示框
* 使用响应头设置资源的打开方式
* content-disposition:attachment;filename=xxx
* 步骤:
* 定义页面,编辑超链接href属性,指向Servlet,传递资源名称filename
* 定义Servlet
* 获取文件名称
* 使用字节输入流加载文件进内存
* 指定response的响应头:content-disposition:attachment;filename=xxx
* 将数据写出到response输出流
#会话技术
会话:一次会话中包含多次请求和响应。
* 一次会话指的是浏览器第一次给服务器资源发送请求,会话建立,直到有一方断开为止
* 功能:在一次会话的范围内的多次请求间,共享数据
* 方式:
* 客户端会话技术:Cookie
* 服务器端会话技术Session
#Cookie
1. 概念:客户端会话技术,将数据保存到客户端
2. 理解:
1. 使用步骤
1. 创建Cookie对象,指定数据
1. new Cookie(String name,String values)
2. 发送Cookie对象数据
1. response.addCookie(Cookie cookie)
3. 获取Cookie,拿到数据
1. request.getCookie()
3. 实现原理
1. 基于响应头set-cookie和请求头cookie实现
4. cookie的细节
1. 一次可不可以发送多个cookie?
1. 可以
1. 可以创建多个Cookie对象,使用response调用多次addCookie方法发送cookie即可
2. cookie在浏览器中保存多长时间?
1. 默认情况下,当浏览器关闭后,Cookie数据被销毁
2. 设置cookie生命周期,持久化存储:
1. setMaxAge(int seconds)
1. 整数:将Cookie数据写到硬盘文件中,持久化存储。Cookie存活时间
2. 负数:默认值
3. 零:删除Cookie信息
3. cookie能不能存中文?
1. 在tomcat8之前cookie中不能直接存储中文数据
需要将中文数据转码—一般采用URL编码(%E3)
2. 在tomcat8之后cookie支持中文数据
4. cookie共享问题?
* 假设在一个tomcat服务器中,部署了多个web项目,这些web项目中能不能共享?
* 默认情况下cookie不能共享
* setPath(String path):设置cookie的获取范围,默认情况下,设置当前的虚拟目录
* 如果要共享 ,则可以将path设置为“/”
* 不同的tomcat服务器间cookie共享问题?
* setDomain(String path):设置设置一级域名相同,那么多个服务器之间cookie可以共享
* setDomain(".baidu.com"):那么tieba.baidu.com和news.baidu.com中可以共享
cookie的特点和作用
1. cookie存储数据在客户端浏览器
2. 浏览器对于单个cookie的大小有限制(4kb),以及对同一个域名下的总cookie数量也有限制(20个)
作用:
1. cookie一般用于存储少量的不太敏感的数据
2. 在不登陆的情况下。完成服务器对客户端的身份识别
案例:记住上一次访问时间
1. 需求 :
1. 访问一个Servlet,如果是第一次访问,则提示:您好,欢迎首次访问
2. 如果不是第一次访问,则提示:欢迎回来,您上次访问时间为:显示时间字符串
2. 分析
1. 可以采用cookie来完成
2. 在服务器中的Servlet判断是否有一个名为lastTime的cookie
1. 有:不是第一次访问
2. 没有:是第一次访问
1. 响应数据:您好
2. 写回Cookie:lastTime
#JSP(Java Server Pages):java 服务端端页面
* 可以理解为:一个特殊的页面,其中既可以指定定义html标签,又可以定义Java代码
* 用于简化书写
1. 原理分析
1. 本质上就是一个servlet
2. jsp脚本:JSP定义Java代码的方式
1. <% 代码 %>:定义的Java代码,在service方法中,service方法中可以定义什么,该脚本就可以定义什么
2. <%! 脚本%>:定义的Java代码,在jsp转换后的Java类的成员位置
3. <%= 代码%>:定义的Java代码会输出到页面上,输出语句中可以定义什么,该脚本中就可以定义什么
JSP的内置对象
* 在jsp页面中不需要获取和创建,可以直接使用的对象
* jsp一共有9个内置对象
* request
* response
* out:字符输出流对象,可以将数据输出到页面上,和response.getWriter()类似
* response.getWriter()和out.write()的区别:
* 在tomcat服务器真正给客户端做出响应之前,会先找response缓冲区数据,再找out缓冲区数据。response。getWriter()数据输出永远在out.writer()之前。
##Session:
1. 概念:服务器端会话技术,在一次会话的多次请求间共享数据,将数据保存到服务器端对象中。HttpSession
2. 练习:
1. HttpSession对象中
1. 获取HttpSession对象
1. HttpSession session=request.getSession();
2. 使用HttpSession对象:
1. Object getAttribute(String name)
2. void setAttribute(String name,Object value)
3. void removeAttribute(String name)
3. 原理:
* Session的实现是依赖于Cookie的
4. 细节:
1. 当客户端关闭后,服务器不关闭,两次获取Session是否为同一个?
1. 默认情况下不是
2. 如果需要相同,则可以创建Cookie,键为JSESSIONID,设置最大的存活时间,让cookie持久化保存
2. 客户端不关闭,服务器关闭后,两次获取的session是同一个吗?
1. 不是同一个,但是要确保数据不丢失
1. session的钝化
1. 在服务器正常关闭之前,将session对象系列化到硬盘上
2. session的活化:
1. 在服务器启动之后,将session文件转化为内存中的session对象即可。
3. Session的什么时候被销毁 ?
1. 服务器关闭
2. session对象调用invalidate()
3. session默认的失效时间为30分钟
选择性配置修改
30
##session的特点:
1. session用于存储一次会话的多次请求的数据,存在服务器端
2. session可以存储任意类型,任意大小的数据
* session与Cookie区别:
* session存储数据在服务器端,Cookie在客户端
* session没有数据大小限制,Cookie有
* session数据安全,Cookie数据相对不安全
##案例:验证码
1. 案例需求:
2. 访问带有验证码的登陆页面login.jsp
3. 用户输入名,密码以及验证码
1. 如果用户名和密码输入有误,跳转登陆页面,提示:用户名火密码错误
2. 如果验证码输入有误,跳转登陆页面,提示:验证码输入错误
3. 如果全部输入正确,则跳转到主页success.jsp,显示:用户名,欢迎您
分析:
* 设置request的编码
* 获取参数Map集合
* 获取验证码
* 将用户信息封装到User对象
* 判断程序生成的验证码和用户输入的验证码是否一致。从session中获取程序生成的验证码
* 一致
* 再判断用户名和密码是否一致
* 正确
* 登陆成功
* 存储数据
* 跳转到success.jsp重定向
* 不正确
* 给提示信息
* 跳转登陆页面
* 不一致
* 给用户提示信息:验证码错误request
* 跳转登陆页面(转发)