晨考
1 请求转发的特点
- 地址栏没有变化
- 服务器动作
- 一次请求
- 可以当做域对象存储数据,在一次请求中共享
2 重定向的特点
- 地址栏会改变
- 浏览器行为
- 两次请求
- 请求域中的数据,重定向后取不出
3 如何创建一个cookie并返回给浏览器
Cookie ck = new Cookie(name,value);
resp.addCookie(ck);
4 如何获得session对象
// 从请求对象获得的session
HttpSession session = req.getSession();
5 session域和request域存储数据的区别
请求域:存储数据,只有在一次请求中共享
session域: 存储数据,只要session没有销毁,无论是请求转发还是重定向都可以取出session的数据
回顾
请求转发 req.getRequestDispatcher(“/ok”).forward(req,resp);
响应重定向 resp.sendRedirect(“/ok”);
注意事项:
- 请求转发时路径从/开始,那么就是服务器根路径开始,
即从项目名开始http://localhost:8080/day41/ok
- 重定向时路径从/开始,那么就是从浏览器的根路径开始,
即从端口开始http://localhost:8080/ok
-
所以在重定向时,建议手动加上项目名,以防止丢失项目名
- req.getContextPath()
-
请求转发,重定向就是用来转发页面或者跳转页面,就是一种控制行为.
Cookie,Session是一种会话技术,都是用来保存会话过程中的数据.
Cookie是浏览器技术
将数据直接存储在浏览器,直接可用查看,相对不安全,存储数据量小4kb
Session是服务器技术
将数据存储在服务器,安全,可靠,数据量大
登录权限认证
在某个系统中,需要先登录才能操作.不登录直接通过url进行操作增删改操作.这样不科学!
LoginServlet 登录,登录成功加入session
DeleteServlet 删除
AddServlet 添加
LogoutServlet 退出
详见代码,自己画图
Servlet的线程安全问题(了解)
- Servlet实例是单实例
- 并发请求时会有线程安全问题
- 加锁synchronized
- 推荐最简单方案
- 可以将一些全局变量变成局部变量
ServletContext
- ServletContext是域对象,对于整个web应用有效
- 服务器启动时创建,关闭时销毁
- 一个web应用只会创建一个ServletContext
- 域对象,也可以像request域,session域一样,存储数据
获得ServletContext
// 从请求中获得
ServletContext servletContext1 = req.getServletContext( );
// 从session获得
HttpSession session = req.getSession( );
ServletContext servletContext2 = session.getServletContext( );
作用
- 获得当前项目名(掌握)
- servletContext.getContextPath()
- 与请求域的方法类似
- req.getContextPath();
- 获得当前项目的真实路径(了解)
- servletContext.getRealPath(“/”)
- 当做域存取数据(了解)
- 存储 servletContext.setAttribute(key,value)
- 取出 servletContext.getAttribute(key)
- 这个域对象存储的数据是整个应用程序内有效,服务器不关闭,就会一直存在
- 可以主动删除 servletContext.removeAttribute(key)
// 作用3: 当做域,存取数据
servletContext1.setAttribute("username","laowangba");
String username = (String) servletContext1.getAttribute("username");
System.out.println("自存自取: " + username );
@WebServlet("/aaa")
public class AAAServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获得对象
ServletContext servletContext = req.getServletContext( );
// 获得数据
String username = (String) servletContext.getAttribute("username");
System.out.println("AAA类获得 " + username );
}
}
销毁
服务器宕机,或者应用从服务器卸载ServletContext对象就会销毁
Filter(过滤器,拦截器)
为什么需要?
目前的情况
- 在每个servlet为了防止乱码,在进行操作之前,都先设置请求和响应的编码格式.
- 在web项目中,在每个Servlet中都要对身份进行认证
即在代码中有重复代码
使用过滤器解决
可以拦截指定请求,然后对请求进行设置,设置后放行或者不放行.
过滤器的入门使用
- 创建一个类
- 实现Filter接口
- 重写方法
- 在doFilter()方法内写拦截的具体内容
- 根据情况决定是否放行
- 如果后续有其他拦截器,放行到下个拦截器
- 如果后续没有拦截器,放行到对应的servlet
- 配置Filter的拦截路径(web.xml)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L9YczRDE-1662464405157)(day41_servlet.assets/image-20220906152157215.png)]
package com.qf.servlet.filter;
import javax.servlet.*;
import java.io.IOException;
/**
* --- 天道酬勤 ---
*
* @author QiuShiju
* @desc
*/
public class MyFilter1 implements Filter {
public MyFilter1(){
System.out.println("MyFilter1创建" );
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("MyFilter1初始" );
}
/**
* @param servletRequest 请求对象,是HttpServletRequest的父类
* @param servletResponse 响应对象,是HttpServletResponse的父类
* @param filterChain 过滤器链,项目中可以同时出现多个拦截器,拦截器之间形成链
* 多个拦截器的执行顺序
* 如果是web.xml配置的,那么就按从上至下
* 如果是注解配置,那么就是按照类字母顺序
* 通过拦截器链对象,来决定是否放行
* @throws IOException
* @throws ServletException
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("拦截器执行了,,,," );
// 放行,如果没有这行代码,就是不放行
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
System.out.println("MyFilter1销毁" );
}
}
<?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">
<filter>
<filter-name>MyFilter1</filter-name>
<!-- 过滤器类 -->
<filter-class>com.qf.servlet.filter.MyFilter1</filter-class>
</filter>
<filter-mapping>
<!-- 名字要与上面的name一致 -->
<filter-name>MyFilter1</filter-name>
<!-- 拦截的路径,与servlet中的映射路径写法一样
支持 绝对路径,模糊匹配,后缀匹配,拦截所有等
-->
<url-pattern>/hw/*</url-pattern>
</filter-mapping>
</web-app>
生命周期
- 服务器启动,filter创建,只创建一次
- 随机立即初始化,只初始化一次
- 每次拦截到都会执行doFilter方法
- 服务器宕机销毁
拦截器链儿
- 项目中可以设置多个拦截器
- 一样创建类,实现接口,重写方法
- 根据情况放行,放行到下一个拦截
- 多个拦截器的执行顺序,按照web.xml上下配置顺序
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9CvYFyKx-1662464405158)(day41_servlet.assets/image-20220906155348311.png)]
<?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">
<filter>
<filter-name>MyFilter3</filter-name>
<!-- 过滤器类 -->
<filter-class>com.qf.servlet.filter.MyFilter3</filter-class>
</filter>
<filter-mapping>
<!-- 名字要与上面的name一致 -->
<filter-name>MyFilter3</filter-name>
<!-- 拦截的路径,与servlet中的映射路径写法一样
支持 绝对路径,模糊匹配,后缀匹配,拦截所有等
-->
<url-pattern>/hw/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>MyFilter2</filter-name>
<!-- 过滤器类 -->
<filter-class>com.qf.servlet.filter.MyFilter2</filter-class>
</filter>
<filter-mapping>
<!-- 名字要与上面的name一致 -->
<filter-name>MyFilter2</filter-name>
<!-- 拦截的路径,与servlet中的映射路径写法一样
支持 绝对路径,模糊匹配,后缀匹配,拦截所有等
-->
<url-pattern>/hw/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>MyFilter1</filter-name>
<!-- 过滤器类 -->
<filter-class>com.qf.servlet.filter.MyFilter1</filter-class>
</filter>
<filter-mapping>
<!-- 名字要与上面的name一致 -->
<filter-name>MyFilter1</filter-name>
<!-- 拦截的路径,与servlet中的映射路径写法一样
支持 绝对路径,模糊匹配,后缀匹配,拦截所有等
-->
<url-pattern>/hw/*</url-pattern>
</filter-mapping>
</web-app>
注解改造
- web.xml不再使用,且同一个类不能同时即使用web.xml配置又使用注解
- 在类上加@WebFilter(“路径”)
@WebFilter("/hw/*")
public class CMyFilter1 implements Filter {
...
}
实战使用[重点]
全局编码格式过滤
以前: 在每个servlet为了防止乱码,在进行操作之前,都先设置请求和响应的编码格式.
现在: 使用拦截器,对所有请求拦截器,设置编码,然后放行
package com.qf.servlet.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/**
* --- 天道酬勤 ---
*
* @author QiuShiju
* @desc 对所有请求都是设置编码格式
*/
@WebFilter("/*")
public class EncodingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 设置编码格式
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
// 放行
chain.doFilter(request,response);
}
@Override
public void destroy() {
}
}
身份认证拦截器
以前: 在web项目中,在每个Servlet中都要对身份进行认证
现在: 使用拦截器,将身份过滤的代码前置到拦截器,对每个请求先身份认证
package com.qf.servlet.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* --- 天道酬勤 ---
*
* @author QiuShiju
* @desc
*/
@WebFilter("/*")
// @WebFilter("/hw/*")
// @WebFilter("*.do")
public class LoginFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
/**
* 对请求的身份进行认证
* 请求中获得session,且session中有登录时存入的数据,说明登录成功,放行
* 请求中获得session,但是session中没有数据,说明没有登录,重定向到登录页
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 获取session
HttpServletRequest req = (HttpServletRequest) request;
HttpSession session = req.getSession( );
String requestURI = req.getRequestURI( );
/**
* 因为是拦截所有 /*
* 所以要放行 静态资源以及第一次登录的请求
*/
if(requestURI.contains("/login") ||requestURI.contains("html") || requestURI.contains("js") || requestURI.contains("css")) {
// 放行
chain.doFilter(request, response);
}
// 从session获得数据
String username = (String) session.getAttribute("username");
// 判断
if (username != null){
// 放行
chain.doFilter(request, response);
} else {
HttpServletResponse resp = (HttpServletResponse) response;
resp.sendRedirect(req.getContextPath()+"/index.html");
}
}
@Override
public void destroy() {
}
}
// 从session获得数据
String username = (String) session.getAttribute("username");
// 判断
if (username != null){
// 放行
chain.doFilter(request, response);
} else {
HttpServletResponse resp = (HttpServletResponse) response;
resp.sendRedirect(req.getContextPath()+"/index.html");
}
}
@Override
public void destroy() { }
}