大致需求是这样的,页面拖动脚本文件,然后拖动到其他的文件夹,其实看起来是没啥难得,后台添加文件,删除当前根目录下的脚本文件就好了,看起来没啥。但还是有坑的。看下面代码。
1.后台代码
/**
* 页面拖拽脚本文件更换位置
* @param user
* @param thisScript
* @param folderPath
* @param revision
* @return
*/
@Transactional
@RequestMapping(value = "/varyPosition",method = RequestMethod.POST)
public String varyPosition(User user,
@RequestParam(value = "thisScript")String thisScript,
@RequestParam(value = "folderPath")String folderPath,
@RequestParam(value = "r", required = false) Long revision) throws ScriptFileException{
//1.判断脚本名称是否符合规则
boolean flag = regexpContants.isExist(thisScript);
//2.判断文件夹名称是否符合规则,不能包含点
int i = folderPath.indexOf(".");
//3.两个都需要符合条件
if (flag && (i == -1)){
//4.首先根据传过来得脚本名称查询到该脚本对象信息,当前thisScript只是脚本名称,thisScript.path就是脚本名称,不包含文件夹名
FileEntry script = fileEntryService.getOne(user, thisScript, revision);
String thisPath = script.getPath();
String scriptPath = folderPath+"/"+script.getPath();
//5.判断目标文件夹内是否有重复名称的脚本存在,如果一样的位置出现重复会出问题,可能会被完全覆盖
if(fileEntryService.getOne(user, scriptPath, revision) == null){
//6.进行save操作
script.setPath(scriptPath);
script.setLastRevision(script.getRevision()+1);
Map<String, String> map = Maps.newHashMap();
map.put("validated", script.getProperties().get("validated"));
map.put("targetHosts", StringUtils.trim(script.getProperties().get("targetHosts")));
script.setProperties(map);
//7.删除根目录下的script文件
fileEntryService.delete(user, thisPath);
//8.最后一步添加操作
fileEntryService.save(user, script);
}else {
throw new ScriptFileException(ResultEnum.SCRIPT_REPEAT);
}
}else {
throw new ScriptFileException(ResultEnum.SCRIPT_RULES);
}
return "script/list";
}
以下编号代表上面的编号:
1.isExist方法,自己定义的正则表达式,主要是判断后缀名,判断是不是groovy、Jython脚本文件
2.这里是文件夹名称里不能有“.”
3.符合条件
4.user对象前端可以不传,前端只穿了需要移动的脚本名称和目标文件夹名称,通过fileEntryService.getOne(user, thisScript, revision)方法,revision可以为0,thisScript就是FileEntry当中的path属性,最后获得一个对象。
5.就是把目标文件名称和脚本名称组合起来,查询一下,看看目标文件夹是否存在该脚本,如果存在的话还强制save,则不会有任何变化或者被覆盖。
6.save操作
//6.进行save操作
script.setPath(scriptPath);
script.setLastRevision(script.getRevision()+1);
Map<String, String> map = Maps.newHashMap();
map.put("validated", script.getProperties().get("validated"));
map.put("targetHosts", StringUtils.trim(script.getProperties().get("targetHosts")));
script.setProperties(map);
这里的script.setPath,则是覆盖值,比如说你要移动到hello文件夹,值应该是hello/test.groovy,Revision可以不写。下面的setProperties必须重新覆盖,要不然会出错。在你第一次添加脚本的十会,debug的时候可以看到FileEntry对象中有个属性properties,初始添加的时候里面只有两个值,一个是targetHosts目标主机,一个好像是validated,看下面图片:
但在你添加脚本完成后,脚本对象中的properties中则会多了很多数据,比如说UUID、checkSum、这些数据是为了保证脚本文件唯一
然后最下面,先新增,后删除。
当你报错ong.tmatesoft.svn.core.SVNException: sVn:E165002: Storage of non-regular property 'svn:entry:nevision' is disallowed ,●through the repository interface,and could indicate a bug in your client的时候,那就是证明添加了同样UUID的脚本。properties中的属性是重复的。
下面是前端代码,前端代码在src/main/webapp/WEB-INF/ftl/script/list.ftl,我觉得前端代码没啥问题,直接赋值过去可以直接使用得。
<!DOCTYPE html>
<html>
<head>
<#include "../common/common.ftl">
<#include "../common/datatables.ftl">
<title><@spring.message "script.list.title"/></title>
<style>
.script-img-unit {
background-image: url('${req.getContextPath()}/img/bg_script_banner_en.png?${nGrinderVersion}');
height: 110px;
padding: 0;
margin-top: 0px;
}
</style>
</head>
<#-- <script src="~/Content/bootstrap-table/extensions/reorder-rows/bootstrap-table-reorder-rows.js"></script>-->
<body>
<div id="wrap">
<#include "../common/navigator.ftl">
<div class="container nav-right">
<div class="script-img-unit "></div>
<div class="well form-inline search-bar" style="margin-top:0;margin-bottom:0" >
<table style="width:100%">
<tr>
<td>
<table style="width:100%">
<colgroup>
<col width="400px"/>
<col width="*"/>
</colgroup>
<tr>
<td>
<input type="text" class="search-query span3" placeholder="Keywords" id="searchText" value="${query!}">
<button type="submit" class="btn" id="search_btn"><i class="icon-search"></i> <@spring.message "common.button.search"/></button>
</td>
<td>
<#if svnUrl?has_content>
<div class="input-prepend pull-right" rel="popover"
title="Subversion" data-placement="bottom"
data-content='<@spring.message "script.message.svn"/>'
data-html="true">
<span class="add-on" style="cursor:default">SVN</span><span class="input-xlarge uneditable-input span7" style="cursor:text">${svnUrl}</span>
</div>
</#if>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>
<table style="width:100%; margin-top:5px">
<colgroup>
<col width="600px"/>
<col width="340px"/>
</colgroup>
<tr>
<td>
<#if !(query??)>
<a class="btn btn-primary" href="#create_script_modal" data-toggle="modal">
<i class="icon-file icon-white"></i>
<@spring.message "script.action.createScript"/>
</a>
<a class="btn" href="#create_folder_modal" data-toggle="modal">
<i class=" icon-folder-open"></i>
<@spring.message "script.action.createFolder"/>
</a>
<a class="btn" href="#upload_file_modal" data-toggle="modal">
<i class="icon-upload"></i>
<@spring.message "script.action.uploadResources"/>
</a>
</#if>
</td>
<td>
<a class="pointer-cursor btn btn-danger pull-right" id="delete_script_button">
<i class="icon-remove icon-white"></i>
<@spring.message "script.action.delete"/>
</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
</div>
<table class="table table-striped table-bordered ellipsis" id="script_list_table" style="width:100%">
<colgroup>
<col width="30">
<col width="32">
<col width="230">
<col>
<col width="150">
<col width="80">
<col width="80">
<col width="80">
</colgroup>
<thead>
<tr>
<th><input type="checkbox" class="checkbox" value=""></th>
<th class="no-click">
<a href="${req.getContextPath()}/script/list/${currentPath}/../" target="_self">
<img src="${req.getContextPath()}/img/up_folder.png?${nGrinderVersion}"/>
</a>
</th>
<th><@spring.message "script.list.name"/></th>
<th class="no-click"><@spring.message "script.list.commit"/></th>
<th><@spring.message "script.list.lastDate"/></th>
<th><@spring.message "script.list.revision"/></th>
<th><@spring.message "script.list.size"/></th>
<th class="no-click"><@spring.message "script.list.download"/></th>
</tr>
</thead>
<tbody>
<@list list_items=files others="table_list" colspan="8"; script>
<tr>
<td><#if script.fileName != ".."><input type="checkbox" class="checkbox" value="${script.fileName}"></#if></td>
<td>
<#if script.fileType.fileCategory.isEditable()>
<i class="icon-file"></i>
<#elseif script.fileType == "dir">
<i class="icon-folder-open"></i>
<#else>
<i class="icon-briefcase"></i>
</#if>
</td>
<td class="ellipsis" draggable="true" id="dragtarget">
<#if script.fileType.fileCategory.isEditable()>
<a href="${req.getContextPath()}/script/detail/${script.path}" target="_self" title="${script.path}">${script.fileName}</a>
<#elseif script.fileType == "dir">
<a href="${req.getContextPath()}/script/list/${script.path}" target="_self" title="${script.path}">${script.fileName}</a>
<#else>
<a href="${req.getContextPath()}/script/download/${script.path}" target="_blank" title="${script.path}">${script.fileName}</a>
</#if>
</td>
<td title="${(script.description)!?html}">${(script.description)!}</td>
<td><#if script.lastModifiedDate??>${script.lastModifiedDate?string('yyyy-MM-dd HH:mm')}</#if></td>
<td>${script.revision}</td>
<td>
<#if script.fileType != "dir">
<#assign floatSize = script.fileSize?number/1024>${floatSize?string("0.##")}
</#if>
</td>
<td class="center">
<#if script.fileType != "dir">
<i class="pointer-cursor icon-download-alt script-download" spath="${script.path}"></i>
</#if>
</td>
</tr>
</@list>
</tbody>
</table>
</div>
<#if !(query??)>
<#include "create_script_modal.ftl">
<#include "create_folder_modal.ftl">validate_btn
<#include "upload_file_modal.ftl">
</#if>
</div>
<#include "../common/copyright.ftl">
<script type="text/javascript">
$(document).ready(function() {
$("#nav_script").addClass("active");
$("#delete_script_button").click(function() {
var list = $("td input:checked");
if(list.length == 0) {
bootbox.alert("<@spring.message "script.message.delete.alert"/>", "<@spring.message "common.button.ok"/>");
return;
}
bootbox.confirm("<@spring.message "script.message.delete.confirm"/>", "<@spring.message "common.button.cancel"/>", "<@spring.message "common.button.ok"/>", function(result) {
if (result) {
var scriptsStr = list.map(function() {
return $(this).val();
}).get().join(",");
var ajaxObj = new AjaxObj("/script/delete/${currentPath}");
ajaxObj.type = "POST";
ajaxObj.params = {'filesString': scriptsStr};
ajaxObj.success = function () {
document.location.reload();
};
ajaxObj.call();
}
});
});
$("#search_btn").on('click', function() {
searchScriptList();
});
enableCheckboxSelectAll("script_list_table");
$("i.script-download").on('click', function() {
window.location = "${req.getContextPath()}/script/download/" + $(this).attr("spath");
});
<#if files?has_content>
$("#script_list_table").dataTable({
"bAutoWidth": false,
"bFilter": false,
"bLengthChange": false,
"bInfo": false,
"iDisplayLength": 10,
"aaSorting": [],
"aoColumns": [{"asSorting": []}, {"asSorting": []}, null, {"asSorting": []}, null, null, null, {"asSorting": []}],
"sPaginationType": "bootstrap",
"oLanguage": {
"oPaginate": {
"sPrevious": "<@spring.message "common.paging.previous"/>",
"sNext": "<@spring.message "common.paging.next"/>"
}
}
});
$(".no-click").off('click');
</#if>
let starEvent = ''
let endEvent = ''
/* 拖动时触发*/
document.addEventListener("dragstart", function(event) {
//dataTransfer.setData()方法设置数据类型和拖动的数据
event.dataTransfer.setData("Text", event.target.id);
//修改拖动元素的透明度
event.target.style.opacity = "0.4";
// console.log(event.target.innerText)
if (event.target.innerText != starEvent) {
starEvent = event.target.innerText
}
});
// 当拖完p元素输出一些文本元素和重置透明度
document.addEventListener("dragend", function(event) {
event.target.style.opacity = "1";
console.log(starEvent,endEvent)
if ((starEvent.indexOf('.groovy') != -1 || starEvent.indexOf('.py') != -1) && starEvent) {
if (endEvent.indexOf('.') == -1 && endEvent) {
// starEvent = ''
// starEvent = ''
<#--document.location.href = "${req.getContextPath()}/script/list"-->
console.log(starEvent,endEvent)
var ajaxObj = new AjaxObj("/script/varyPosition");
ajaxObj.type = "POST";
ajaxObj.params = {'thisScript': starEvent,'folderPath':endEvent};
ajaxObj.success = function () {
};
ajaxObj.call();
}
}
});
/* 拖动完成后触发 */
// 当p元素完成拖动进入droptarget,改变div的边框样式
document.addEventListener("dragenter", function(event) {
if ( event.target.className.indexOf("ellipsis") != -1 ) {
if (endEvent != event.target.innerText) {
endEvent = event.target.innerText
}
}else {
endEvent = ''
}
});
// 默认情况下,数据/元素不能在其他元素中被拖放。对于drop我们必须防止元素的默认处理
document.addEventListener("dragover", function(event) {
event.preventDefault();
});
// function fixHelper(e,ui){
// // console.log(ui.context.children[2].innerText)
// ui.children().each(function() {
// $(this).width($(this).width());
// });
// return ui;
// }
// $( "#script_list_table tbody").sortable({
// helper: fixHelper,
// axis:"y",
// revert: false, //释放时,增加动画
// });
// $( "#script_list_table").disableSelection();
});
function searchScriptList() {
document.location.href = "${req.getContextPath()}/script/search?query=" + $("#searchText").val();
}
</script>
</body>
</html>