他人博客:https://www.jianshu.com/p/8a4a5e273538
Spring Boot集成ace editor:https://www.jianshu.com/p/f35c59314ec4
PlantUML在线编辑器选用ace_editor,一款开源的编辑器。
需求
UGC页面提供一个跳转到在线编辑器页面的按钮,点击按钮以后跳转,进入到编辑器页面,且编辑器自动加载了PlantUML DSL文本以及对应的UML图。用户可以在编辑器修改DSL语言,并点击生成UML图按钮,在右边对应生成UML图,最后点击保存按钮,数据写入数据库。
具体实现
1.在线编辑器前端页面实现
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head th:replace="~{fragments/header :: header}">
<style>
.btn2{
color:#fff;
background-color: #373a3c;
border-color: #373a3c;
}
.all-container{
width:100%;
padding-right: 15px;
padding-left: 15px;
margin-right: auto;
margin-left: auto;
}
</style>
</head>
<body>
<div class="all-container" >
<div class="container blog-content-container">
<div class="row">
<input type="hidden" name="id" th:value="${blogModel.umlDiagram.id}" id="umlId">
<div class="col-sm-5">
<!--<div class="row h-100 align-items-center justify-content-center">
</div>-->
<div class="row h-100 justify-content-center align-items-center">
<div id="editor" style="height: 500px; width: 500px">
</div>
</div>
</div>
<div class="col-sm-1"></div>
<div class="col-sm-6">
<img id="uml_url" src="/images/xq.jpeg" th:src="${blogModel.umlDiagram.uml_image}" style="max-width: 500px;max-height:400px">
</div>
<div class="text-center">
<button type="button" style="margin-top:8px;" id="uml_generate" class="btn text-center">
Generate UML
</button>
</div>
</div>
<div style="text-align: center">
<button class="btn text-center" style="margin-top:8px;" id="saveUml" type="submit"
>Save</button>
</div>
<div th:replace="~{fragments/footer ::footer}">...</div>
</div><!-- /container -->
<!--<script>
var editor = ace.edit("editor");
editor.setTheme("ace/theme/cobalt");
editor.setFontSize(18);
//editor.getValue()
</script>-->
<script th:inline="javascript">
var plantuml_txt=[[${blogModel.umlDiagram.fil_txt}]];
</script>
<script src="../../js/ace/online_editor.js" th:src="@{/js/ace/online_editor.js}"></script>
</div>
</body>
</html>
2.在线编辑器基本设置
$(function(){
var editor = ace.edit('editor');
editor.setTheme("ace/theme/cobalt");
editor.setFontSize(12);
editor.setValue(plantuml_txt);
editor.getValue();
$("#uml_generate").click(function () {
var csrfToken = $("meta[name='_csrf']").attr("content");
var csrfHeader = $("meta[name='_csrf_header']").attr("content");
$.ajax({
url:'/generate',
type:'POST',
data:{'fil_text':editor.getValue(),
},
beforeSend: function(request) {
request.setRequestHeader(csrfHeader, csrfToken); // 添加 CSRF Token
},
success:function (data) {
console.log("数据:"+data);
//$('#image_name').val(data);
var img_url='/images/'+data;
console.log(img_url);
$('#uml_url').attr('src',img_url);
},
error : function() {
toastr.error("error!");
}
})
});
$("#saveUml").click(function() {
// 获取 CSRF Token
var csrfToken = $("meta[name='_csrf']").attr("content");
var csrfHeader = $("meta[name='_csrf_header']").attr("content");
$.ajax({
url: '/'+$(this).attr("userName") + '/umledit',
type: 'POST',
contentType: "application/json; charset=utf-8",
data:JSON.stringify({
"id":$('#umlId').val(),
"fil_txt":editor.getValue(),
"uml_image":$('#uml_url').attr('src'),
}),
beforeSend: function(request) {
request.setRequestHeader(csrfHeader, csrfToken); // 添加 CSRF Token
},
success: function(data){
if (data.success) {
// 成功后,重定向
//window.location = data.body;
console.log("数据:"+data)
toastr.success("保存成功!");
} else {
toastr.error("error!"+data.message);
}
},
error : function() {
toastr.error("error!");
}
})
});
})
3.后端实现
@Controller
public class EditorController {
@Autowired
private UmlService umlService;
@GetMapping("/{username}/online_edit/{id}")
public ModelAndView onlineEditor(@PathVariable("username") String username,
@PathVariable("id") Long id, Model model) {
User principal = null;
Optional<UmlDiagram> optionalUml = umlService.getUmlDiagramById(id);
UmlDiagram umlDiagram = null;
if (optionalUml.isPresent()) {
umlDiagram = optionalUml.get();
}
boolean isBlogOwner = false;
if (SecurityContextHolder.getContext().getAuthentication() != null
&& SecurityContextHolder.getContext().getAuthentication().isAuthenticated() && !SecurityContextHolder
.getContext().getAuthentication().getPrincipal().toString().equals("anonymousUser")) {
principal = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principal != null && username.equals(principal.getUsername())) {
isBlogOwner = true;
}
}
model.addAttribute("isBlogOwner", isBlogOwner);
model.addAttribute("umlDiagram", umlDiagram);
return new ModelAndView("online_editor", "blogModel", model);
}
@PostMapping("/{username}/umledit")
@PreAuthorize("authentication.name.equals(#username)")
public ResponseEntity<Response> saveUml(@PathVariable("username") String username, @RequestBody UmlDiagram umlDiagram) {
System.out.println("username:"+username);
try {
Optional<UmlDiagram> optionalUmlDiagram = umlService.getUmlDiagramById(umlDiagram.getId());
if (optionalUmlDiagram.isPresent()) {
UmlDiagram orignalUml = optionalUmlDiagram.get();
orignalUml.setFil_txt(umlDiagram.getFil_txt());
//uml图片
orignalUml.setUml_image(umlDiagram.getUml_image());
umlService.saveUmlDiagram(orignalUml);
}else{
return ResponseEntity.ok().body(new Response(false,"不存在该UGC!"));
}
} catch (ConstraintViolationException e) {
return ResponseEntity.ok().body(new Response(false, ConstraintViolationExceptionHandler.getMessage(e)));
} catch (Exception e) {
return ResponseEntity.ok().body(new Response(false, e.getMessage()));
}
/* String redirectUrl = "/u/" + username + "/umlblogs/" + umlDiagram.getId();*/
return ResponseEntity.ok().body(new Response(true, "处理成功",null));
}
}