精确控制会议氛围:创新排座功能为您打造完美会议

目录

前言

1、效果图演示

2、功能分析

3、插件分享--html2canvas

4、sql分析

5、 源码展示

5.1、我的会议界面--Mymeeting.jsp

5.2、我的会议js页面--Mymeeting.js

5.3、会议排座jsp页面--seatPic.jsp

5.4、 UserServlet--后端,查询会议对应的人员

5.5、查询相关会议人员--Dao层

5.6、 我的会议后端--查询会议、排座图片下载

5.7、配置tomcat服务器磁盘访问路径

5.8、我的会议dao层--会议排座图片修改,我的会议遍历

6、总结


前言

上一篇博客讲到了会议的发布功能,之后就是送给自己的上级进行审批了,但是此时有个新的功能插件,就是排座功能,本章就带大家一起来看看,我们如何实现排座功能吧


1、效果图演示

2、功能分析

  • 我的会议查询
    • 获取到当前用户的id,查询当前用户创建未结束的所有会议

  • 会议排座功能
    • 当我们点击送审时,需要先进行排座
    • 首先,排座中包含个查询的功能,也就是查询当前会议参与的人员,然后展示在我们的排座界面中
    • 点击下载,我们就会使用到我们的插件,来将元素进行截取,然后转化成一个对象,再将对象转化成一个数据,再利用工具类进行解码然后将其画成一张图片
    • 最后,将其存到数据库,如果成功,关闭子页面,然后,关闭弹窗,至此整个功能完成


3、插件分享--html2canvas

html2canvas是一个JavaScript库,用于将HTML元素转换为Canvas图像。具体的使用看我的源码如何操作吧,上面有具体的注释

简要介绍如下:

  1. 功能:html2canvas库的主要功能是将指定的HTML元素(包括其子元素)渲染为一个Canvas图像对象。

  2. 兼容性:html2canvas支持大多数现代浏览器,包括Chrome、Firefox、Safari等。

  3. 使用方法:

    a. 引入html2canvas库:在HTML文件中引入html2canvas库的JavaScript文件,可以通过直接下载并引用的方式,或者使用CDN来加载该库。

    b. 选择需要转换的HTML元素:通过选择器、ID或类名等方式选择需要转换的HTML元素。

    c. 调用html2canvas函数:使用html2canvas(element [, options])方法,传入需要转换的HTML元素作为参数,可选地传入一些配置选项来调整转换的行为。

    d. 处理结果:html2canvas方法会返回一个Promise对象,你可以使用.then()方法来处理转换完成后的Canvas对象。

    e. 使用Canvas对象:将转换后的Canvas对象用于你的需求,比如将其显示在页面上、保存为图片等。

  4. 配置选项:html2canvas提供了一些配置选项,可以通过传入一个包含配置参数的对象来自定义转换的行为,例如设置转换的宽高、忽略某些元素等。

总的来说,html2canvas是一个方便实用的库,可用于将HTML元素转换为Canvas图像,使得在前端将网页内容截图、生成图片等操作变得更加简单易用。


4、sql分析

  • 当我们点击我的会议时,查询当前用户所有的会议,而当前用户,也就是自己发布会议的人,而这个人,在发布会议的时候就已经设定死了,就是登录的人,所以,只需根据会议的主持人字段来进行条件查询
    SELECT a.id,a.title,a.content,a.canyuze,a.liexize,a.zhuchiren,b.`name`,a.location
    ,DATE_FORMAT(a.startTime,'%Y-%m-%d %H:%i:%s') as startTime
    ,DATE_FORMAT(a.endTime,'%Y-%m-%d %H:%i:%s') as endTime
    ,a.state
    ,(case a.state
    when 0 then '取消会议'
    when 1 then '新建'
    when 2 then '待审核'
    when 3 then '驳回'
    when 4 then '待开'
    when 5 then '进行中'
    when 6 then '开启投票'
    else '结束会' end
    ) as meetingState
    ,a.seatPic,a.remark,a.auditor,c.`name` as auditorName
    FROM t_oa_meeting_info a
    inner join t_oa_user b on a.zhuchiren = b.id
    left JOIN t_oa_user c on a.auditor = c.id
    where 1=1
    and and zhuchiren = ?
    

  • 点击排座功能时,需要将人员数据带到子界面,也就是排座界面进行遍历,所以可以将会议的id,带到子界面,根据id查询出所有的参会人员
    	String sql="select * from t_oa_user where FIND_IN_SET(id,"
    					+ "(select concat(canyuze,',',liexize,',',zhuchiren) "
    					+ "from t_oa_meeting_info where id=?))";

这个SQL语句的意思是从表t_oa_user中选择所有行,其中id在另一个子查询中的结果集中找到。子查询是从表t_oa_meeting_info中选择一行,然后将该行的canyuze、liexize和zhuchiren列值连接成一个字符串。然后使用FIND_IN_SET函数来检查表t_oa_user的id是否在这个字符串中存在。该字符串使用逗号作为分隔符。这条SQL语句的目的是找到在t_oa_meeting_info表中特定id的记录中,指定的id是否存在于t_oa_user表中。


     当用户点击确认排座,也就是下载了这个按钮的时候呢,就要修改会议的会议排座图片了

public int updatesetpic(MeetingInfo info) throws Exception {
			String sql="update t_oa_meeting_info set seatPic=? where id=?";
			return super.executeUpdate(sql, info, new String[] {"seatPic","id"});
		}

5、 源码展示

5.1、我的会议界面--Mymeeting.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@include file="/common/public.jsp"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="static/js/meeting/myMeeting.js"></script>
</head>
<style>
body{
	margin:15px;
}
 .layui-table-cell {height: inherit;}
 .layui-layer-page .layui-layer-content {  overflow: visible !important;}
</style>
<body>
<!-- 搜索栏 -->
<div class="layui-form-item" style="margin:15px 0px;">
  <div class="layui-inline">
    <label class="layui-form-label">会议标题</label>
    <div class="layui-input-inline">
      <input type="hidden" id="zhuchiren" value="${user.id }"/>
      <input type="text" id="title" autocomplete="off" class="layui-input">
    </div>
  </div>
  <div class="layui-inline">
    <button id="btn_search" type="button" class="layui-btn"><i class="layui-icon layui-icon-search"></i> 查询</button>
  </div>
</div>
<!-- 数据表格 -->
<table id="tb" lay-filter="tb" class="layui-table" style="margin-top:-15px"></table>
<!-- 对话框(送审) -->
<div id="audit" style="display:none;">
	<form style="margin:20px 15px;" class="layui-form layui-form-pane" lay-filter="audit">
		<div class="layui-inline">
		   <label class="layui-form-label">送审人</label>
		   <div class="layui-input-inline">
		      <input type="hidden" id="meetingId" value=""/>
		      <select id="auditor" style="poistion:relative;z-index:1000">
				<option value="">---请选择---</option>
		      </select>
		   </div>
		   <div class="layui-input-inline">
		     <button id="btn_auditor" class="layui-btn">送审</button>
		   </div>
		</div>
	</form>
</div>
<!-- 对话框(反馈详情) -->
<div id="feedback" style="display:none;padding-left:15px; margin-bottom:60px;">
	<fieldset class="layui-elem-field layui-field-title">
	  <legend>参会人员</legend>
	</fieldset>
	<blockquote class="layui-elem-quote" id="meeting_ok"></blockquote>
	<fieldset class="layui-elem-field layui-field-title">
	  <legend>缺席人员</legend>
	</fieldset>
	<blockquote class="layui-elem-quote" id="meeting_no"></blockquote>
	<fieldset class="layui-elem-field layui-field-title">
	  <legend>未读人员</legend>
	</fieldset>
	<blockquote class="layui-elem-quote" id="meeting_noread"></blockquote>
</div>
<script type="text/html" id="tbar">
  {{#  if(d.state==1 || d.state==3){ }}
  <a class="layui-btn layui-btn-xs" lay-event="seat">会议排座</a>
  <a class="layui-btn layui-btn-xs" lay-event="send">送审</a>
  <a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
  {{#  } }}
  {{#  if(d.state!=1 && d.state!=2 && d.state!=3){ }}
  <a class="layui-btn layui-btn-xs" lay-event="back">反馈详情</a>
  {{#  } }}
</script>
</body>
</html>

5.2、我的会议js页面--Mymeeting.js

let layer,table,$,form;
var row;
layui.use(['layer','table','jquery','form'],function(){
	layer=layui.layer,
	table=layui.table,
	form=layui.form,
	$=layui.jquery;
	
	initTable();
	
	query();
	//查询事件
	$('#btn_search').click(function(){
		query();
	});
	
	
	//初始化审批人
	initFormSelects();
	
	
	//送审
	$('#btn_auditor').click(function(){
		$.post($("#ctx").val()+'/info.action',{
			'methodName':'updateAuditorById',
			'id':$('#meetingId').val(),
			'auditor':$('#auditor').val()
		},function(rs){
			if(rs.success){
				//关闭对话框
				layer.closeAll();
				//刷新列表
				query();
			}else{
				layer.msg(rs.msg,{icon:5},function(){});
			}
		},'json');
		return false;
	});
});

//1.初始化数据表格
function initTable(){
	table.render({          //执行渲染
//		url: 'info.action?methodName=myInfos',
        elem: '#tb',   //指定原始表格元素选择器(推荐id选择器)
        height: 700,         //自定义高度
        loading: false,      //是否显示加载条(默认 true)
        page:true,
        cols: [[             //设置表头
            {field: 'id', title: '会议编号', width: 90},
            {field: 'title', title: '会议标题', width: 120},
            {field: 'location', title: '会议地点', width: 140},
            {field: 'startTime', title: '开始时间', width: 120},
            {field: 'endTime', title: '结束时间', width: 120},
            {field: 'meetingState', title: '会议状态', width: 120},
            {field: 'seatPic', title: '会议排座', width: 120,
            	templet: function(d){
                    if(d.seatPic==null || d.seatPic=="")
                    	return "尚未排座";
                    else
                    	return "<img width='100px' height='60px' src='"+d.seatPic+"'/>";
                }
            },
            {field: 'auditorName', title: '审批人', width: 120},
            {field: '', title: '操作', width: 200,toolbar:'#tbar'},
            
        ]]
   });
}

//2.点击查询
function query(){
	table.reload('tb', {
        url: 'info.action',     //请求地址
        method: 'POST',                    //请求方式,GET或者POST
        loading: true,                     //是否显示加载条(默认 true)
        page: true,                        //是否分页
        where: {                           //设定异步数据接口的额外参数,任意设
        	'methodName':'myInfos',
        	'zhuchiren':$('#zhuchiren').val(),
        	'title':$('#title').val(),
        },  
        request: {                         //自定义分页请求参数名
            pageName: 'page', //页码的参数名称,默认:page
            limitName: 'rows' //每页数据量的参数名,默认:limit
        },
        done: function (res, curr, count) {
        	console.log(res);
        }
   });
	
	//工具条事件
	table.on('tool(tb)', function(obj){ //注:tool 是工具条事件名,test 是 table 原始容器的属性 lay-filter="对应的值"
	  row = obj.data; //获得当前行数据
	  var layEvent = obj.event; //获得 lay-event 对应的值(也可以是表头的 event 参数对应的值)
	  var tr = obj.tr; //获得当前行 tr 的 DOM 对象(如果有的话)
	  console.log(row);
	  if(layEvent === 'seat'){ //会议排座
		open(row.id)
	  } else if(layEvent === 'send'){ //送审
//会议送审功能
//		  判断是进行排座了
		  if(row.seatPic==null || row.seatPic==""){
			  layer.msg('先请完成会议排座,再进行送审操作!',function(){});
			  return false;
		  }
		  //在打开送审页面之前,先请完成会议ID的赋值操作
		  $('#meetingId').val(row.id);
		  openLayerAudit();
//		  点击送审时,弹出层中会议送审人员查出来,也就是调用dao方法
//		  打开会议送审页面层

		  
		  
		  
	  } else if(layEvent==="back"){ //反馈详情
		  openLayerFeedBack(row.id);
	  } else {
		  layer.msg('删除');
	  }
	});
}















//打开会议排座对话框
function open(id){
	layer.open({
        type: 2,                    //layer提供了5种层类型。可传入的值有:0(信息框,默认)1(页面层)2(iframe层)3(加载层)4(tips层)
        title: '会议排座',                   //对话框标题
        area: ['460px', '340px'],   //宽高
        skin: 'layui-layer-rim',    //样式类名
        content: $("#ctx").val()+'/jsp/meeting/seatPic.jsp?id='+id,                //弹出内容。可以传入普通的html内容,还可以指定DOM,更可以随着type的不同而不同
    });
}





//会议送审
function openLayerAudit(){
	//每次打开都对送审人进行初始化默认值设置
	$('#auditor').val("");
	//必须重新渲染
	form.render('select');
	//弹出对话框
    layer.open({
        type: 1,                    //layer提供了5种层类型。可传入的值有:0(信息框,默认)1(页面层)2(iframe层)3(加载层)4(tips层)
        title:'会议送审',
        area: ['426px', '140px'],   //宽高
        skin: 'layui-layer-rim',    //样式类名
        content: $('#audit'),   //弹出内容。可以传入普通的html内容,还可以指定DOM,更可以随着type的不同而不同
    });
}



//初始化审批人
function initFormSelects(){
	$.getJSON($("#ctx").val()+'/addmeeting.action',{
		'methodName':'listtwo'
	},function(rs){
		console.log(rs);
		let data=rs.data;
		$.each(data,function(i,e){
			$('#auditor').append(new Option(e.name,e.value));
		});
		//重新渲染
		form.render('select');
	});
}




//打开查看本会议的反馈详情
function openLayerFeedBack(id){
	$.getJSON('feedBack.action',{
		methodName:'queryMeetingBackByMeetingId',
		meetingId:id
	},function(data){
		$('#meeting_ok').html("");
		$('#meeting_no').html("");
		$('#meeting_noread').html("");
		if(data.success){
			console.log(data.data);
			$.each(data.data,function(i,e){
				if(e.result==1)
					$('#meeting_ok').html(e.names);
				else if(e.result==2)
					$('#meeting_no').html(e.names);
				else
					$('#meeting_noread').html(e.names);
			});
			//弹出对话框
		    layer.open({
		        type: 1,                    //layer提供了5种层类型。可传入的值有:0(信息框,默认)1(页面层)2(iframe层)3(加载层)4(tips层)
		        title:'反馈详情',
		        area: ['626px', '320px'],   //宽高
		        skin: 'layui-layer-rim',    //样式类名
		     
		        content: $('#feedback'),   //弹出内容。可以传入普通的html内容,还可以指定DOM,更可以随着type的不同而不同
		       
		        btn:['关闭'],
		        yes:function(index,layero){
		        	layer.closeAll();
		        }
		    });
		}
	});
}



中间是会议审批、会议反馈的一些功能,后面会讲,我们只需要关乎会议排座的方法就行

5.3、会议排座jsp页面--seatPic.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html >
<html>
<head>
<base href="${pageContext.request.contextPath }/"/>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link href="static/js/layui/css/layui.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="static/js/jquery-3.3.1.min.js"></script>
<script type="text/javascript" src="static/js/layui/layui.js"></script>
<script type="text/javascript" src="static/js/plugins/html2canvas/html2canvas.js"></script>
<title>会议座位安排</title>
</head>
<style type="text/css">
* {
	padding: 0;
	margin: 0;
}
		
body{
	width: 100%;
	height: 100%;
	/* background: red; */
}

.tips {
	/* position: absolute; */
	background: pink;
	display: inline-block;
	height: 60px;
	/* width: 60px; */
	line-height: 60px;
	text-align: center;
	margin: 5px;
	padding: 0 10px;
}

.add {
	position: fixed;
	right: 10px;
	top: 10px;
	display:inline;
}

#tu {
	width: 100%;
	height: 100%;
	/* background: lightblue; */
		/*background: url('u=3318199716,2583790385&fm=26&gp=0.jpg');*/
}
.layui-input{
	height:30px;
}
</style>
<body id="screen_body">
    <div id="tu"></div>
    <!-- 下面不要使用layui的表单行内模式,会导致canvas的toDataURL()数据为 data:, -->
	<div class="add">
		<div style="display:inline-block;">
			<input id="dan_input" type="text" value="" class="layui-input">
		</div>
		<div style="display:inline-block;">
			<button onclick="return addDanMu()" class="layui-btn layui-btn-sm">添加座位</button><input id="jie_input" type="button" class="layui-btn layui-btn-sm" value='下载'>
		</div>
	</div>
</body>
<script type="text/javascript">
var $id = function(id) {
	return document.getElementById(id);
}
//会议排座拖拽
var dragF = {
	locked: false,
	lastObj: undefined,
	drag: function(obj) {
		$id(obj).onmousedown = function(e) {
			var e = e ? e : window.event;
			if (!window.event) {
				e.preventDefault();
			} /* 阻止标注<a href='/site/js-5791-1.html' target='_blank'><u>浏览器</u></a>下拖动a,img的默认事件 */
			dragF.locked = true;
			$id(obj).style.position = "absolute";
			$id(obj).style.zIndex = "100";
			if (dragF.lastObj && dragF.lastObj != $id(obj)) { /* 多元素拖动需要恢复上次元素状态 */
				dragF.lastObj.style.zIndex = "1";
			}

			dragF.lastObj = $id(obj);
			var tempX = $id(obj).offsetLeft;
			var tempY = $id(obj).offsetTop;

			dragF.x = e.clientX;
			dragF.y = e.clientY;
			document.onmousemove = function(e) {
				var e = e ? e : window.event;
				if (dragF.locked == false) return false;
				$id(obj).style.left = tempX + e.clientX - dragF.x + "px";
				$id(obj).style.top = tempY + e.clientY - dragF.y + "px";
				if (window.event) {
					e.returnValue = false;
				} /* 阻止ie下a,img的默认事件 */

			}

			document.onmouseup = function() {
				dragF.locked = false;
			}
		}
	}
}
</script>

<script type="text/javascript">
var layer;
layui.use(['layer'],function(){
	layer=layui.layer;

    //初始化会议排座:根据会议ID获取参会的所有人员的名字(主持人+参会人+列席人)
	initMeetingUsers();
	
	//绘制会议排座图片
	$("#jie_input").on("click", function(event) {
		//隐藏了会议排座div
		$('.add').hide();
		event.preventDefault();
		//使用html2canvas库将id为"screen_body"的元素及其内容转换为Canvas对象。
		html2canvas(document.getElementById("screen_body")).then(function(canvas) {
		//将Canvas对象转换为数据URL,以便在上传或显示之前进行操作。
			var dataUrl = canvas.toDataURL();
			console.log(dataUrl);
			//创建一个名为param的空对象,用于存储上传的参数
			var param = {};
		//	将数据URL赋值给param对象的属性"seatPic",这是要上传的会议排座图片
			param['seatPic'] = dataUrl;
		//动态获取传过来的参数id
			param['id'] = '${param.id}';
		//	将"updatesetpic"赋值给param对象的属性"methodName",表示要调用的方法名。应根据具体情况进行修改。
			param['methodName']='updatesetpic';
		//输出param对象的内容到控制台,以便调试和查看参数。
			console.log(param);
			//此处需要完成会议排座图片上传操作
			$.post('${pageContext.request.contextPath }/info.action',param,function(rs){
				if(rs.success){
					//先得到当前iframe层的索引
					var index = parent.layer.getFrameIndex(window.name); 
					//再执行关闭
					parent.layer.close(index); 
					//调用父页面的刷新方法
					parent.query();
				}else{
					//如果上传失败,则使用layer.msg()方法弹出错误消息,并显示错误图标。
					layer.msg(rs.msg,{icon:5},function(){});
				}
			},'json');
		});
	});
});

function initMeetingUsers(){
	//http://localhost:8080/xxx/seatPic.jsp?id=12  -> ${param.id}
	//发送请求到useraction,然后查询当前会议的人员
	$.getJSON('${pageContext.request.contextPath }/User.action',{
		'methodName':'meetingpeople',
		'meetingId':'${param.id}'
	},function(rs){
		console.log(rs);
		let data=rs.data;
		$.each(data,function(i,e){
			//有几个人,就增加几个模块
			$('#dan_input').val(e.name);
			addDanMu();
		});
	});
}


//添加会议排座
function addDanMu() {
	var dan = document.getElementById("dan_input").value;
	if (dan == "") {
		alert("请输入弹幕~");
		return false;
	} else {
		document.getElementById("dan_input").value = ""; //清空 弹幕输入框
		// var br = document.createElement("BR");  // <br />
		var node = document.createElement("DIV"); // <div>
		var tipsArr = document.getElementsByClassName('tips');
		var i;
		// console.log(parseInt(tipsArr[tipsArr.length-1].id.substr(4))+1);
		if (tipsArr.length == 0) {
			i = 1
		} else {

			i = parseInt(tipsArr[tipsArr.length - 1].id.substr(4)) + 1;
		}
		// var aNode = document.createElement("P");   // <p>
		node.setAttribute("class", "tips");
		node.setAttribute("id", "tips" + i);
		node.setAttribute("onmouseover", "dragF.drag('tips" + i + "');");
		var textnode = document.createTextNode(dan); // 创建个 文本节点, 将用户输入的弹幕,存入 创建的 元素节点 <p>  中
		// aNode.appendChild(textnode);
		node.appendChild(textnode);
		// document.body.appendChild(br);
		// document.body.appendChild(node);

		document.getElementById("tu").appendChild(node);
		return true;
	}
}
	</script>
</html>

会议排座界面的js也在这个页面中了,其中大家可能不懂的就是插件的使用了,我在这里也暂时解释不清楚,但是跟着我的代码走就行了,上面有我的注释,基本还是看的懂的,插件的底层我也还没有研究明白,


还有一个就是

	param['id'] = '${param.id}';

关于这一行也有小伙伴不懂,这个$ { param.id }其实就是动态获取父页面传过来的参数id啦,回头去看我的会议js 

在这一行其实就把会议的id带过来了 

5.4、 UserServlet--后端,查询会议对应的人员

package Servlet;

import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.zking.framework.ActionSupport;
import com.zking.framework.ModelDriver;
import com.zking.util.PageBean;
import com.zking.util.R;
import com.zking.util.ResponseUtil;

import Dao.Userdao;
import Entity.User;

public class UserServlet extends ActionSupport implements ModelDriver<User>{
private User user= new User();
private PageBean page= new PageBean();
private Userdao ud= new Userdao();


	


			
			
			
			
			//查询对应会议的人员
			public String meetingpeople(HttpServletRequest req, HttpServletResponse resp) {
				try {
					String m= req.getParameter("meetingId");
					PageBean pageBean = new PageBean();
					List<User> users = ud.queryUserByMeetingId(Integer.valueOf(m));
					// layui 的code 返回一定要是 0,不能是200,否者返回不了数据
					ResponseUtil.writeJson(resp, R.ok(0, "会议用户数据初始化成功", users));
				} catch (Exception e) {
					e.printStackTrace();
					try {
						ResponseUtil.writeJson(resp, R.error(0, "查询失败"));
					} catch (Exception e1) {
						e1.printStackTrace();
					}
				}
				return null;
			}	
			
			
			

			
			
	@Override
	public User getModel() {
		// TODO Auto-generated method stub
		return user;
	}

	
	
}

5.5、查询相关会议人员--Dao层

		//	根据会议ID查询相关用户
		public List<User> queryUserByMeetingId(Integer integer) throws Exception{
			String sql="select * from t_oa_user where FIND_IN_SET(id,"
					+ "(select concat(canyuze,',',liexize,',',zhuchiren) "
					+ "from t_oa_meeting_info where id="+integer+"))";
			return super.executeQuery(sql, User.class, null);
		}
		
		

5.6、 我的会议后端--查询会议、排座图片下载

package Servlet;

import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.zking.framework.ActionSupport;
import com.zking.framework.ModelDriver;
import com.zking.util.Base64ImageUtils;
import com.zking.util.PageBean;
import com.zking.util.PropertiesUtil;
import com.zking.util.R;
import com.zking.util.ResponseUtil;

import Dao.Meetingdao;
import Entity.MeetingInfo;

public class MeetinginfoServlet  extends ActionSupport implements ModelDriver<MeetingInfo>{

	
	
	private MeetingInfo m= new MeetingInfo();
	
	Meetingdao md= new Meetingdao();
	
	
	// 我的会议
		public String myInfos(HttpServletRequest req, HttpServletResponse resp) {
			try {
				PageBean pageBean = new PageBean();
				pageBean.setRequest(req);
				List<Map<String, Object>> infos = md.myInfos(m, pageBean);
				ResponseUtil.writeJson(resp, R.ok(0, "我的会议查询成功!!!", pageBean.getTotal(), infos));
			} catch (Exception e) {
				e.printStackTrace();
				try {
					ResponseUtil.writeJson(resp, R.error(0, "我的会议查询失败!!!"));
				} catch (Exception e1) {
					e1.printStackTrace();
				}
			}
			return null;
		}
	
	
//		下载图片的方法
		
		public String updatesetpic(HttpServletRequest req, HttpServletResponse resp) throws Exception {
//			获取到图片的存放地址
			String dirPath = PropertiesUtil.getValue("dirPath");
		
//			获取浏览器请求路径,为了后续保存到数据库
			String serverPath = PropertiesUtil.getValue("serverPath");
			
//			随机生成一个图片的名
			String filename = UUID.randomUUID().toString().replaceAll("-", "")+ ".png";
//			将base64编码生成一张图片,保存在目录中
			Base64ImageUtils.GenerateImage(m.getSeatPic().replaceAll("data:image/png;base64,", ""), dirPath+filename);
//			将seatpic中的内容改变成请求地址
			m.setSeatPic(serverPath+filename);
//			修改会议排座中数据库图片对应的数据库列段
			int r = md.updatesetpic(m);
			if(r>0) {
				ResponseUtil.writeJson(resp, R.ok(200, "会议排座成功"));
			}else  {
				ResponseUtil.writeJson(resp, R.ok(0, "会议排座失败"));
			}
			return null;	
			}
		
			
		
//		我的审批
		public String myAudit(HttpServletRequest req, HttpServletResponse resp) {
			try {
				PageBean pageBean = new PageBean();
				pageBean.setRequest(req);
				List<Map<String, Object>> infos = md.myAudit(m, pageBean);
				ResponseUtil.writeJson(resp, R.ok(0, "我的审批查询成功!!!", pageBean.getTotal(), infos));
			} catch (Exception e) {
				e.printStackTrace();
				try {
					ResponseUtil.writeJson(resp, R.error(0, "我的审批查询失败"));
				} catch (Exception e1) {
					e1.printStackTrace();
				}
			}
			return null;
		}
		
		
//		会议送审
		public String updateAuditorById(HttpServletRequest req, HttpServletResponse resp) throws Exception {
			
			int r = md.updateAuditorById(m);
			if(r>0) {
				ResponseUtil.writeJson(resp, R.ok(200, "会议送审成功"));
			}else  {
				ResponseUtil.writeJson(resp, R.ok(0, "会议送审失败"));
			}
			return null;	
		}
		
		
//		待开会议、历史会议
		public String queryMeetingInfoByState(HttpServletRequest req, HttpServletResponse resp) {
			try {
				PageBean pageBean = new PageBean();
				pageBean.setRequest(req);
				List<Map<String, Object>> infos = md.queryMeetingInfoByState(m, pageBean);
				ResponseUtil.writeJson(resp, R.ok(0, "会议查询成功!!!", pageBean.getTotal(), infos));
			} catch (Exception e) {
				e.printStackTrace();
				try {
					ResponseUtil.writeJson(resp, R.error(0, "会议查询失败"));
				} catch (Exception e1) {
					e1.printStackTrace();
				}
			}
			return null;
		}	
		
		
		
//		所有会议
		public String allInfos(HttpServletRequest req, HttpServletResponse resp) {
			try {
				PageBean pageBean = new PageBean();
				pageBean.setRequest(req);
				List<Map<String, Object>> infos = md.allInfos(m, pageBean);
				ResponseUtil.writeJson(resp, R.ok(0, "会议查询成功!!!", pageBean.getTotal(), infos));
			} catch (Exception e) {
				e.printStackTrace();
				try {
					ResponseUtil.writeJson(resp, R.error(0, "会议查询失败"));
				} catch (Exception e1) {
					e1.printStackTrace();
				}
			}
			return null;
		}
		
		
	
	
	
	@Override
	public MeetingInfo getModel() {
		// TODO Auto-generated method stub
		return m;
	}

	
	
	
	
	
	
	
	
	
	
	
	
	
	
}

关于图片下载相信大家会有一些疑问,这里就来解释一下,关于PropertiesUtil

package com.zking.util;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class PropertiesUtil {
	public static String getValue(String key) throws IOException {
		Properties p = new Properties();
		InputStream in = PropertiesUtil.class.getResourceAsStream("/resource.properties");
		p.load(in);
		return p.getProperty(key);
	}
	
}

配置文件

dirPath=D:/pic/picc/
serverPath=/upload/paizuo/
dirPathSign=D:/pic/picc/sign/
serverPathSign=/upload/sign/


 

大家可以看到,这个类通过流的方式获取到了配置文件,并且通过Properties类中的getProperty方法通过配置文件中的键获取值,从而拿到了配置文件中定义的本地路径已经服务器的访问路径,然后,通过Base64ImageUtils类来生成图片并且输出到了指定的本地目录,其中为什么getseatpic有值呢,因为前端传过来的时候,直接赋值给了会议对象(mvc框架中配置的)

package com.zking.util;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

public class Base64ImageUtils {
	

	public static String GetImageStr(String imgFilePath) {// 将图片文件转化为字节数组字符串,并对其进行Base64编码处理
		byte[] data = null;

		// 读取图片字节数组
		try {
			InputStream in = new FileInputStream(imgFilePath);
			data = new byte[in.available()];
			in.read(data);
			in.close();
		} catch (IOException e) {
			e.printStackTrace();
		}

		// 对字节数组Base64编码
		BASE64Encoder encoder = new BASE64Encoder();
		return encoder.encode(data);// 返回Base64编码过的字节数组字符串
	}

	public static boolean GenerateImage(String imgStr, String imgFilePath) {// 对字节数组字符串进行Base64解码并生成图片
		if (imgStr == null) // 图像数据为空
			return false;
		BASE64Decoder decoder = new BASE64Decoder();
		try {
			// Base64解码
			byte[] bytes = decoder.decodeBuffer(imgStr);
			for (int i = 0; i < bytes.length; ++i) {
				if (bytes[i] < 0) {// 调整异常数据
					bytes[i] += 256;
				}
			}
			// 生成jpeg图片
			OutputStream out = new FileOutputStream(imgFilePath);
			out.write(bytes);
			out.flush();
			out.close();
			return true;
		} catch (Exception e) {
			return false;
		}
	}
}

后端拿到了这个图像数据,去掉了data:image/png;base64,这个字符串,然后解码放入指定的目录,也就是我们从配置文件获取过来的本地目录dirpath,然后拼接上通过UUID.randomUUID().toString().replaceAll("-", "")生成一个随机的图片文件名,确保文件名的唯一性,并将其后缀设置为.png。从而将图片成功下载


但是从常规企业级项目来说,我们服务区访问路径是不会带项目名字的,所以我们还需要配置服务器的访问数据库的图片路径,也就是从配置文件获取到的服务器访问路径拼接图片名称,最后我们将其设置到我们的对象中,将对象利用sql语句也就是dao方法进行修改,

5.7、配置tomcat服务器磁盘访问路径

上一个段落讲到了我们的图片实际路径和数据库的路径是不一样的,所以如果只做到这一步,服务器是找不到我们的图片的,所以我们就需要去配置我们服务器访问的映射路径了

1、

双击tomccat服务器

 

点击最底下的moudles 

 点击右侧第二个按钮

 第一行输入的是我们配置文件中的磁盘目录

第二行就是我们服务器的访问目录,点击ok即可

这样我们的服务器,就可以通过我们配置的磁盘映射路径找到对应的图片了

5.8、我的会议dao层--会议排座图片修改,我的会议遍历

package Dao;

import java.util.List;
import java.util.Map;

import com.zking.util.BaseDao;
import com.zking.util.PageBean;
import com.zking.util.StringUtils;

import Entity.MeetingInfo;
import Entity.User;

public class Meetingdao extends BaseDao<MeetingInfo> {

	

		

//		通用的会议查询SQL语句,包含会议信息表数据,主持人姓名、审批人姓名、会议状态
		private String getSQL() {
			return "SELECT a.id,a.title,a.content,a.canyuze,a.liexize,a.zhuchiren,b.`name`,a.location\r\n" + 
					",DATE_FORMAT(a.startTime,'%Y-%m-%d %H:%i:%s') as startTime\r\n" + 
					",DATE_FORMAT(a.endTime,'%Y-%m-%d %H:%i:%s') as endTime\r\n" + 
					",a.state\r\n" + 
					",(case a.state\r\n" + 
					"when 0 then '取消会议'\r\n" + 
					"when 1 then '新建'\r\n" + 
					"when 2 then '待审核'\r\n" + 
					"when 3 then '驳回'\r\n" + 
					"when 4 then '待开'\r\n" + 
					"when 5 then '进行中'\r\n" + 
					"when 6 then '开启投票'\r\n" + 
					"else '结束会' end\r\n" + 
					") as meetingState\r\n" + 
					",a.seatPic,a.remark,a.auditor,c.`name` as auditorName\r\n" + 
					"FROM t_oa_meeting_info a\r\n" + 
					"inner join t_oa_user b on a.zhuchiren = b.id\r\n" + 
					"left JOIN t_oa_user c on a.auditor = c.id where 1=1 ";
		}
		
		
		
		
//		我的会议
		public List<Map<String, Object>> myInfos(MeetingInfo info, PageBean pageBean) throws Exception {
			String sql = getSQL();
			String title = info.getTitle();
			if(StringUtils.isNotBlank(title)) {
				sql += " and title like '%"+title+"%'";
			}
			//根据当前登陆用户ID作为主持人字段的条件
			sql+=" and zhuchiren="+info.getZhuchiren();
			//按照会议ID降序排序
			sql+=" order by a.id desc";
			System.out.println(sql);
			return super.executeQuery(sql, pageBean);
		}
		
		
		
		
		
//		根据会议ID更新会议的排座图片
		public int updatesetpic(MeetingInfo info) throws Exception {
			String sql="update t_oa_meeting_info set seatPic=? where id=?";
			return super.executeUpdate(sql, info, new String[] {"seatPic","id"});
		}

}

至此,我的会议排座功能就完毕了

6、总结

总的来说,会议排座这个功能还是比较吸引人的,对于一些政府的项目会经常用到,所以在此记录一下,再把流程分析一遍吧,


  • 点击排座---
  • 弹出子页面--遍历参会人员--点击下载,获取图片数据-----
  • 传入后端--后端获取服务器访问路径,获取磁盘路径,创建随机图片名,通过工具类将图片数据解码然后传入指定的磁盘路径拼接图片名,设置数据库路径为服务器路径拼接图片名--
  • 判断如果修改成功,抓取到父页面的iframe索引,然后通过索引关闭父页面的弹窗,调取父页面的刷新方法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
秘书智能排座软件 V1.2 版本于2011年9月16日正式发布。软件程序升级后,增加和修复了一些功能,放宽了一些限制,运行效率和执行效率更高,系统更加安全可靠。 办文、办会、办事既是办公室日常工作的重要组成部分,也是办公室履行职能的重要手段。 在办公室工作的同仁,每天都会举办、组织、参与、协调各级各类会议。召开会议就涉及到参加会议人员的排座问题,就餐问题,还有会议代表集体合影留念问题。 一般情况下,我们要事先排定与会或就餐者的座次,但目前的座次表全凭工作人员手工制作,工作繁琐,容易出错。参会人员临时因故不能参会或增加人员,这种情况在会议开始头一天甚至会前经常发生,工作人员就需要在已经编排好的Excel表格中再插入或删除人员的姓名,轮番的“复制、粘贴”。如果参会人员多,往往错一个人,就需要一两个小时,甚至半天时间才能修改完成,有的甚至来不及修改座次表。 在办公室十几年经常从事这种机械重复而又繁琐无味的工作,使我们萌生了开发一种智能软件,把我们已经形成并普遍接受的规矩通过计算机程序来完成。 我们基于GIS基础地理信息系统平台,采用VC6+GDI的模式,来实现会场和会标自定义、会议座位区域自定义、就座列排多少自定义、就餐接待主题自定义、表格宽窄餐桌大小自定义、姓名横竖排列自定义、姓名字号大小自定义、过道多少和宽窄自定义、排列优先级自定义、列号排号自定义、备注和页码自定义、正反排列自由选择、A3A416开纸张自由选择(需根据计算机配备打印机的要求)、纸张横排竖排自主选择、个体群体排列自由选择、座次排列全部自动生成、参会人员、就餐人员和照相人员座次自动生成等等,能将几个小时的手工操作缩短为几秒钟,极大地减轻办公室秘书和会务人员的劳动强度和劳动量,有效提高工作效率,表现出不凡的作用和优越的性能。 目前一般使用的软件只是把名单通过程序导入到Excel表中,然后人工进行添加内容并修改完善。而秘书智能排座软件不同于这种Excel制表,您可以直观地将表格任意移动、修改、调整、设置,其科学性、灵活性、实用性都是其他同类软件无法比拟的。 秘书智能排座软件现有16种基本排列方法,交叉使用可延伸出更多的排列方法,只要是目前我们会议需要的,都可以通过秘书智能排座软件来实现。 秘书智能排座软件:轻轻一点帮您解决会议、照相、宴会、考试座位排列、座次安排的全部问题。 会务精灵,秘书必备,快乐工作,白领时尚。 会议考试,宴会照相,只需一点,轻松给力。 《秘书智能排座位软件 V1.2 版本正式发布》一文转载自〖秘书工作〗网站,版权属于原作者,转载请注明出处。文章地址:http://www.msgz.org/Article/Class71/17537.html
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值