利用监听器设置在线人数以及文件上传

这篇博客介绍了如何在Java Servlet中利用监听器来跟踪在线人数,并详细讲解了单文件和多文件上传的实现过程,包括前端JSP的表单设置、后端Servlet的处理方法,以及使用servlet3.0的@MultipartConfig注解来避免上传异常。同时,作者还提出了代码优化方案,建议创建一个工具类UploadUtil以提高代码复用性。
摘要由CSDN通过智能技术生成

监听器

功能
Servlet中的监听器功能是负责监听WEB的各种操作,当相关的事件触发之后将产生事件,并对此事件进行处理,在WEB中可以对application、session、request三种操作进行监听。
分类
分别对application,session,request事件的监听
实现
实现监听功能,主要是由一个普通类,实现监听器的接口,在web.xml中配置监听器或者添加注解

以下是主要使用的六个监听器接口

接口作用
ServletRequestListener监听request的生命周期
ServletRequestAttributeListener监听request域里面attribute参数的添加、删除或是修改
HttpSessionListener监听session的 生命周期(创建以及销毁)
HttpSessionAttributeListenersession域中的Attribute参数的添加、删除或是修改
ServletContextListener监听application生命周期
ServletContextAttributeListener全局域application域里面attribute参数的添加修改或是删除

监听器监听在线人数

思路
首先,需要利用session的有关参数的监听器。在登录时使用session域存储登录的用户信息user。当监听到参数的改变之后,在监听器里面实现记录当前在线人数操作。其次,记录的人数需存储于application域里面。使用application的生命周期监听器ServletContextListener来存储在Attribute中。
代码
CountOnLineListener.java文件
import java.util.ArrayList;
import java.util.List;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;

import priv.zs.upload.beans.User;

/**
 * Application Lifecycle Listener implementation class CountOnLine
 *
 */
@WebListener
public class CountOnLine implements ServletContextListener, HttpSessionAttributeListener {

	private ServletContext app ;
	
	/**
     * Default constructor. 
     */
    public CountOnLine() {
    }

	/**
     * @see ServletContextListener#contextDestroyed(ServletContextEvent)
     */
    public void contextDestroyed(ServletContextEvent sce)  { 
    }

	/**
     * @see HttpSessionAttributeListener#attributeAdded(HttpSessionBindingEvent)
     */
    //session参数添加  在线人数
    public void attributeAdded(HttpSessionBindingEvent se)  { 
//    	System.out.println("session添加一个参数");
//    	System.out.println("监听到的添加属性名:" + se.getName());
		//设置参数,若是添加的参数名不是"user",证明不是用户添加,而是session域中存储量其他的参数
    	if(se.getName().equals("user")) {
    		/*
    		 * 添加注解消除掉警告  此警告是由于app.getAttribute()方法所获得的的 参数为Object类型,
    		 * 若不是User对象则会出现异常,无法将参数值转换为List<User>类型
    		 */
			@SuppressWarnings("unchecked")
			List<User> users = (List<User>) app.getAttribute("users");
	    	User user = (User) se.getValue();
	    	users.add(user);
	    	int count = (int) app.getAttribute("count");
	    	count++;
	    	app.setAttribute("count", count);
	    	/*
	    	 * count为基本数据类型,若是不存储进参数里面,则会无法修改在线人数
	    	 * 而List<User>为引用数据类型,不需要存储回去亦可改变参数
	    	 */
    	}
//    	System.out.println("count数目:" + count);
    }

	/**
     * @see HttpSessionAttributeListener#attributeRemoved(HttpSessionBindingEvent)
     */
    //session参数减少  离线人数
    public void attributeRemoved(HttpSessionBindingEvent se)  { 
//    	System.out.println("有人注销.....");
    	@SuppressWarnings("unchecked")
    	List<User> users = (List<User>) app.getAttribute("users");
    	User user = (User) se.getValue();
    	users.remove(user);
    	int count = (int) app.getAttribute("count");
    	count--;
    	app.setAttribute("count", count);
    }

	/**
     * @see HttpSessionAttributeListener#attributeReplaced(HttpSessionBindingEvent)
     */
    public void attributeReplaced(HttpSessionBindingEvent se)  { 
    }

	/**
     * @see ServletContextListener#contextInitialized(ServletContextEvent)
     */
    public void contextInitialized(ServletContextEvent sce)  { 
    	//初始化应用全局对象app
    	app = sce.getServletContext();
    	/**
    	 * 一开始启动服务器时,无人登录,所以在线人数初始化为0
    	 * 新建一个键值对count -- value 存储在线人数 
    	 * 新建集合存储用户名
    	 */
    	//设置在线人数参数
    	app.setAttribute("count", 0);
    	//设置在线用户集合
    	app.setAttribute("users", new ArrayList<User>());
    }
示例servlet
跳转onLine.jsp的ServletdoGet方法
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		ServletContext app = this.getServletContext();
		int count = (int) app.getAttribute("count");
		@SuppressWarnings("unchecked")
		List<User> users = (List<User>) app.getAttribute("users");
		request.setAttribute("count", count);
		request.setAttribute("users", users);
		request.getRequestDispatcher("onLine.jsp").forward(request, response);
	}
示例jsp
onLine.jsp
<body>
	在线人数:${requestScope.count}<br /><br />
	在线用户信息:
	<c:forEach var="user" items="${requestScope.users}">
		<p>用户名:${user.account}</p>
	</c:forEach>
</body>

文件上传

在文件上传时,前端 jsp 文件使用form表单实现,提交方法设置为post,因为get方法会将参数显示在URL地址栏,大小为4-6KB,多了则会导致数据丢失。
文件的大小显然不可能固定在4-6KB以下,因此使用post方式提交则可以尽可能保证数据不会丢失
且,此方法使用的是servlet3.0的方法,需要使用注解@MultipartConfig,否则将会报异常

单文件上传

单文件上传,在servlet里面使用request,getPart(String name);方法,name为<input />标签的name值。
代码以上传图片为例子

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		HttpSession session = request.getSession();
		//获取图片(单张图片)
		Part part = request.getPart("headImg");
		//获取文件提交的路径
		String filePath = part.getSubmittedFileName();
//		System.out.println(filePath);
		//获取文件后缀名
		String suffix = filePath.substring(filePath.lastIndexOf("."));
//		System.out.println("后缀名:" + suffix);
		//生成文件名
		//new Date().getTime()得到自1970年以来至今的毫秒数,一般不会重复,可借此生成唯一文件名
		String fileName = new Date().getTime() + suffix;
		//生成文件保存路径(文件对应的upload目录下)
		String path = request.getServletContext().getRealPath("/upload");		//"E:\\" + fileName;
//		System.out.println("upload路径:" + path);
		//写入文件  
		//设置文件路径
		String savePath = path + "\\" + fileName;
//		System.out.println("文件保存路径:" + savePath);
		//用write(String str)方法写入文件,str为文件的存储地址
		part.write(savePath);
		//将地址存储进session域
		session.setAttribute("headImg", fileName);
//		request.getRequestDispatcher("show.jsp").forward(request, response);
		response.sendRedirect("show.jsp");
}

多文件上传

多文件上传与单文件有一定的相似之处,唯一不同只是获取文件方法不同。多文件上传使用request.getParts();
单文件上传getPart(String name),需要有参数,多文件则不需要。
同样,以上传图片为例

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//设置编码
		request.setCharacterEncoding("utf-8");
		response.setCharacterEncoding("utf-8");
		response.setContentType("text/html; charset=UTF-8");
		//获取文件
		List<Part> parts = (List<Part>) request.getParts();
		//定义一个集合来存储文件保存的路径
		List<String> photos = new ArrayList<String>();
		HttpSession session = request.getSession();
		for(Part part:parts) {
			try {
				//添加睡眠时间,避免getTime()方法获取时间,以5ms隔开相同的情况
				Thread.sleep(5);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			//获取文件上传路径
			String filePath = part.getSubmittedFileName();
//			System.out.println(filePath);
			//获取文件后缀名
			String suffix = filePath.substring(filePath.lastIndexOf("."));
//			System.out.println("后缀名:" + suffix);
			//生成文件名
			String fileName = new Date().getTime() + suffix;
			//生成文件保存路径(文件对应的upload目录下)
			String path = request.getServletContext().getRealPath("/upload");		//"E:\\" + fileName;
//			System.out.println("upload路径:" + path);
			
			//写入文件
			String savePath = path + "\\" + fileName;
//			System.out.println("文件保存路径:" + savePath);
			part.write(savePath);
			//将地址存储进session域
			photos.add(fileName);
			session.setAttribute("photos", photos);
		}
//		request.getRequestDispatcher("show.jsp").forward(request, response);
		response.sendRedirect("show.jsp");
	}

优化代码

代码可以改进。实质上,多文件上传于单文件上传几乎一样,只不过是多文件爱你上传获取到的是一个集合,而单文件却是一个对象。并且其中的方法直接复制粘贴套过来嵌套循环使用,实现多文件的上传,最多是在多文件里面添加了一个线程睡眠的方法。因此,写一个工具类,使用静态方法由类直接调用,传入参数HttpServletRequest接口与Part对象即可。

UploadUtil.java工具类

import java.io.IOException;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.Part;

public class UploadUtil {
	
	public static void upload(HttpServletRequest request, Part part, List<String> address) throws IOException, InterruptedException {
		//添加睡眠时间,避免getTime相同的情况
		Thread.sleep(5);
		String filePath = part.getSubmittedFileName();
//		System.out.println(filePath);
		//获取文件后缀名
		String suffix = filePath.substring(filePath.lastIndexOf("."));
//		System.out.println("后缀名:" + suffix);
		//生成文件名
		String fileName = new Date().getTime() + suffix;
		//生成文件保存路径(文件对应的upload目录下)
		String path = request.getServletContext().getRealPath("/upload");		//"E:\\" + fileName;
//		System.out.println("upload路径:" + path);
		
		//写入文件
		String savePath = path + "\\" + fileName;
//		System.out.println("文件保存路径:" + savePath);
		part.write(savePath);
		//将地址存储进session域
		address.add(fileName);
	}
}

多文件上传servlet类UploadMore.java中的doPost()方法

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//设置编码
		request.setCharacterEncoding("utf-8");
		response.setCharacterEncoding("utf-8");
		response.setContentType("text/html; charset=UTF-8");
		//获取文件
		List<Part> parts = (List<Part>) request.getParts();
		List<String> photos = new ArrayList<String>();
		HttpSession session = request.getSession();
		try {
			for(Part part:parts) {
				//添加睡眠时间,避免getTime相同的情况
				UploadUtil.upload(request, part, photos);
				session.setAttribute("photos", photos);
			}
			response.sendRedirect("show.jsp");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

单文件UploadSingle.java的doPost()方法

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		HttpSession session = request.getSession();
		List<String> address = new ArrayList<String>();
		//获取图片(单张图片)
		Part part = request.getPart("headImg");
		try {
			UploadUtil.upload(request, part, address);
			session.setAttribute("headImg", address.get(0));
			response.sendRedirect("show.jsp");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

页面布局

前端jsp页面
主页show.jsp登陆之后的

<a href="count.do">查看在线人数</a>

<h1>用户信息如下:</h1>
<p>账号:${sessionScope.user.account}</p>
<p>密码:${sessionScope.user.password}</p>
<p>
	头像:
	<c:choose>
		<c:when test="${empty sessionScope.headImg}">
			<a href="single.jsp">上传头像</a>
		</c:when>
		<c:otherwise>
			<img src="${pageContext.request.contextPath}/upload/${sessionScope.headImg}"  width="150"/><a href="single.jsp">上传头像</a>
		</c:otherwise>
	</c:choose>
	
</p>
<p>
	相册:
	<c:forEach var="photo" items="${sessionScope.photos }">
		<img src="${pageContext.request.contextPath}/upload/${photo}"  width="150" />
	</c:forEach>
	<a href="more.jsp">上传相册</a>
</p>
<a href="logout.do">注销登录</a>

项目示例:
https://download.csdn.net/download/zb1812606603/12490798

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值