Web03

Web03

1.Listener

Listener 监听器

Listener 是 JavaEE 的规范,接口

监听某种事物的变化通过回调函数反馈给客户(程序)相应处理

 

ServletContextListener

监听 ServletContext 对象的创建和销毁:

  • web 工程启动的时候创建,调用contextInitialized(ServletContextEvent sce);

  • 在 web 工程停止的时候销毁,调用contextDestroyed(ServletContextEvent sce);

使用:

  • 编写一个类去实现 ServletContextListener

  • 实现其两个回调方法

  • 到 web.xml 中去配置监听器

    <listener> 
    <listener-class>
          com.atguigu.listener.MyServletContextListenerImpl
       </listener-class>
    </listener>

 

2.文件上传

非常常见的功能

2.1 上传

1#步骤

  1. form 标签,method=post

  2. form 标签的 encType 属性值必须为 multipart/form-data

    (提交的数据多段拼接,每个表单项对应一个数据段,以二进制流形式发给服务器)

  3. form 标签中使用 input type=file 添加上传的文件

  4. 服务器代码(Servlet 程序)接收,处理上传的数据

2#commons-fileupload.jar

导入两个 jar 包:

  • commons-fileupload-1.2.1.jar

  • commons-io-1.4.jar

常用的类:

ServletFileUpload 类:解析上传的数据

  • boolean ServletFileUpload.isMultipartContent(HttpServletRequest request);

    判断当前上传的数据格式是否是多段的格式

  • public List<FileItem> parseRequest(HttpServletRequest request) 解析上传的数据

FileItem 类:表示每一个表单项

  • boolean FileItem.isFormField() 判断当前表单项:true 普通表单项/false 上传文件类型

  • String FileItem.getFieldName() 获取表单项 name 属性

  • String FileItem.getString() 获取当前表单项的

  • String FileItem.getName() 获取上传的文件名

  • void FileItem.write( file )上传文件写到 file 指向的硬盘位置

 

3#fileupload 类库

实例:

public class UploadServlet extends HttpServlet {
   @Override
   protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       System.out.println("File upload....");
       //判断是否是多段数据,只有多段数据才是文件上传
       if(ServletFileUpload.isMultipartContent(req)){
           //创建 FileItemFactory 工厂实现类
           FileItemFactory fileItemFactory = new DiskFileItemFactory();
           // 创建用于解析上传数据的工具类 ServletFileUpload 类
           ServletFileUpload servletFileUpload = new ServletFileUpload(fileItemFactory);

           try {
               // 解析上传的数据,得到每一个表单项 FileItem
               List<FileItem> list = servletFileUpload.parseRequest(req);
               // 循环判断,每一个表单项,是普通类型,还是上传的文件
               for (FileItem item : list) {
                   if(item.isFormField()){
                       // 普通表单项
                       System.out.println(item.getFieldName()+":"+item.getString("UTF-8"));
                  }else {
                       // 上传的文件
                       System.out.println(item.getFieldName()+":"+item.getName());
                       item.write(new File("E://"+item.getName()));
                  }
              }
          } catch (Exception e) {
               e.printStackTrace();
          }
      }
  }
}

 

2.2 下载

实例:

file文件夹放在web目录下,访问此servlet即下载此文件

public class DownloadServlet extends HttpServlet {
   @Override
   protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       //1.下载的文件名
       String filename = "a.jpg";
       //2.读取下载的文件通过ServletContext对象
       ServletContext servletContext = getServletContext();
       //3.设置返回类型
       String mimeType = servletContext.getMimeType("/file/" + filename);
       resp.setContentType(mimeType);
       //4.设置下载头部
       //附件:attachment
       //下载的文件名:filename

       resp.setHeader("Content-Disposition", "attachment; filename=" + filename);

       //获取文件输入流:/ 表示工程地址
       InputStream resStream = servletContext.getResourceAsStream("/file/" + filename);
       //获取输出流
       OutputStream os = resp.getOutputStream();
       //读取输入流到输出流,输出给客户端
       IOUtils.copy(resStream, os);
  }
}

中文乱码

判断请求头中 User-Agent

String ua = request.getHeader("User-Agent"); // 判断是什么浏览器 
if (ua.contains("Firefox")) { }

1.URLEncoder IE 和谷歌浏览器

// 把中文名进行 UTF-8 编码操作。 String str = "attachment; fileName=" + URLEncoder.encode("中文.jpg", "UTF-8");
// 然后把编码后的字符串设置到响应头中
response.setHeader("Content-Disposition", str);

2.BASE64 编解码 火狐浏览器

// 使用下面的格式进行 BASE64 编码后 
String str = "attachment; fileName=" + "=?utf-8?B?" + new BASE64Encoder().encode("中文.jpg".getBytes("utf-8")) + "?=";
// 设置到响应头中
response.setHeader("Content-Disposition", str);

3.Cookie

Cookie 是服务器通知客户端保存键值对的一种技术

每个 Cookie 的大小不能超过 4kb

每次请求都发送给服务器

3.1 创建Cookie

  • 客户端请求

  • 服务器创建 Cookie cookie = new Cookie("key","value");可多个

  • 回应客户端 response.addCookie(cookie);

  • 客户端收到响应头 Set-Cookie,新建或修改Cookie

3.2 服务器获取Cookie

  • 客户端发送Cookie

  • 服务器获取 request.getCookies(); 返回Cookie[]数组

public class CookieUtils { 
/**
* 查找指定名称的 Cookie 对象
* @param name
* @param cookies
* @return
*/
public static Cookie findCookie(String name , Cookie[] cookies){
if (name == null || cookies == null || cookies.length == 0) {
return null;
}
for (Cookie cookie : cookies) {
if (name.equals(cookie.getName())) {
return cookie;
}
}
return null;
}

}

3.3 修改Cookie

方法一

  • 创建一个同名 key 的 Cookie 对象,同时赋于新的 Cookie 值

    • Cookie cookie = new Cookie("key1","newValue1");

  • 通知客户端保存修改

    • resp.addCookie(cookie);

方法二

  • 查找要修改的 Cookie 对象 使用上节工具类方法

    • Cookie cookie = CookieUtils.findCookie("key2", req.getCookies());

  • 调用 setValue()方法赋新的 Cookie 值

    • cookie.setValue("newValue2");

  • 调用 response.addCookie()通知客户端保存修改

    • resp.addCookie(cookie);

 

3.4 Cookie生命控制

管理 Cookie 什么时候被销毁

setMaxAge()

  • 正数,表示在指定的秒数后过期

  • 负数,表示浏览器一关,Cookie 就会被删除(默认值是-1)

  • 零,表示马上删除 Cookie

设置后再addCookie(cookie);保存修改

 

3.5 Cookie有效路径

path 属性可以有效的过滤哪些 Cookie 可以发送给服务器

path 属性是通过请求的地址来进行有效的过滤

CookieA path=/工程路径

请求地址为 http://ip:port/工程路径/xxxx 时会发送CookieA

 

4.Session

Session 是一个接口(HttpSession)

Session 会话 用来维护客户端和服务器之间关联

每个客户端都有自己的一个 Session 会话

保存用户登录之后的信息,保留在服务器

4.1 创建 获取

request.getSession()

  • 第一次调用:创建 Session 会话

  • 之后调用:获取前面创建好的 Session 会话对象

isNew()

  • true 表示刚创建

  • false 表示获取之前创建

getId()

  • 得到 Session 的会话 id 值

4.2 获取数据

req.getSession().setAttribute("key1", "value1");

Object attribute = req.getSession().getAttribute("key1");

4.3 Session生命周期

public void setMaxInactiveInterval(int interval)

设置 Session 的超时时间(以秒为单位)

  • 值为正数的时候,设定 Session 的超时时长 默认30 分钟

  • 负数表示永不超时

public int getMaxInactiveInterval()

获取 Session 的超时时间

public void invalidate()

让当前 Session 会话马上超时无效

web.xml中配置全局

<!--表示当前 web 工程。创建出来 的所有 Session 默认是 20 分钟 超时时长-->

<session-config>

<session-timeout>20</session-timeout>

</session-config>

 

5.Filter

5.1 过滤 登录

Filter 过滤器是 JavaEE 的规范、接口

只关心请求地址是否匹配,不关心请求资源是否存在

作用是:拦截请求,过滤响应

 

 

 

使用步骤:

  • 编写一个类去实现 Filter 接口

  • 实现过滤方法 doFilter()

public class AdminFilter implements Filter { 
   /*** doFilter 方法,专门用于拦截请求。可以做权限检查 */
   @Override
   public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
       HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
       HttpSession session = httpServletRequest.getSession();
       Object user = session.getAttribute("user");
       // 如果等于 null,说明还没有登录
       if (user == null){                 servletRequest.getRequestDispatcher("/login.jsp").forward(servletRequest,servletResponse); return;
        } else {
           // 让程序继续往下访问用户的目标资源
           filterChain.doFilter(servletRequest,servletResponse);
      }
  }
}
  • 到 web.xml 中去配置 Filter 的拦截路径

<!--filter 标签用于配置一个 Filter 过滤器--> 
<filter>
   <!--给 filter 起一个别名-->
   <filter-name>AdminFilter</filter-name>
   <!--配置 filter 的全类名-->
   <filter-class>com.atguigu.filter.AdminFilter</filter-class>
</filter>
<!--filter-mapping 配置 Filter 过滤器的拦截路径-->
<filter-mapping>
   <!--filter-name 表示当前的拦截路径给哪个 filter 使用-->
   <filter-name>AdminFilter</filter-name>
   <!--url-pattern 配置拦截路径
/ 表示请求地址为:http://ip:port/工程路径/ 映射到 IDEA 的 web 目录
/admin/* 表示请求地址为:http://ip:port/工程路径/admin/*
-->
   <url-pattern>/admin/*</url-pattern>
</filter-mapping>

 

5.2 Filter生命周期

web 工程启动时执行:(Filter 已经创建)

  • 构造器方法

  • init 初始化方法

每次拦截到请求,就会执行:

  • doFilter 过滤方法

停止 web 工程时:

  • destroy 销毁

5.3 FilterConfig类

Filter 过滤器的配置文件类

每次创建 Filter ,同时创建一个 FilterConfig 类

获取 filter 过滤器的配置内容:

  • 获取 Filter 的名称 filter-name 的内容 :filterConfig.getFilterName()

  • 获取在 Filter 中配置的 init-param 初始化参数 :filterConfig.getInitParameter("username")

  • 获取 ServletContext 对象filterConfig.getServletContext()

web.xml 配置

<filter> 
   <!--给 filter 起一个别名-->
   <filter-name>AdminFilter</filter-name>
   <!--配置 filter 的全类名-->
   <filter-class>com.atguigu.filter.AdminFilter</filter-class>
   <init-param>
       <param-name>username</param-name>
       <param-value>root</param-value>
   </init-param>
</filter>

5.4 FilterChain过滤器链

多个过滤器:

  • 所有filter和目标资源默认同一线程

  • 多个filter共同执行时共享一个Request对象

  • 执行的优先顺序为web.xml的配置顺序

FilterChain.doFilter()方法:

  • 执行下一个过滤器

  • 若没有则执行目标资源

5.5 Filter拦截路径

精确匹配:

<url-pattern>/target.jsp</url-pattern>

请求地址必须为:http://ip:port/工程路径/target.jsp

目录匹配:

<url-pattern>/admin/*</url-pattern>

请求地址必须为:http://ip:port/工程路径/admin/*

后缀名匹配:

<url-pattern>*.xxx</url-pattern>

请求地址必须以.xxx 结尾才会拦截到

 

6.ThreadLocal

解决多线程的数据安全问题

特点:

  • ThreadLocal 可以为当前线程关联一个数据(可以像 Map 一样存取数据,key 为当前线程

  • 每一个 ThreadLocal 对象只能为当前线程关联一个数据,如果要为当前线程关联多个数据,就需要使用多个 ThreadLocal 对象实例

  • 每个 ThreadLocal 对象实例定义的时候,一般都是 static 类型

  • ThreadLocal 中保存数据,在线程销毁后由 JVM 虚拟自动释放

方法:

  • ThreadLocal.get: 获取ThreadLocal中当前线程共享变量的值。

  • ThreadLocal.set: 设置ThreadLocal中当前线程共享变量的值。

  • ThreadLocal.remove: 移除ThreadLocal中当前线程共享变量的值。

  • ThreadLocal.initialValue: ThreadLocal没有被当前线程赋值时或当前线程刚调用remove方法后调用get方法,返回此方法值

6.1 组合管理事务

使用 ThreadLocal 来确保所有 dao 操作都在同一个 Connection 连接对象中完成

 

posted @ 2021-05-19 19:37  FremontUltimate  阅读(42)  评论(0)    收藏  举报