JAVA多文档编辑器
前言:当前版本的文档编辑器实现了文档编辑时常用的插件支持;文档管理;编辑器插件管理;用户设置等功能。其他优化功能后期支持继续扩展。该系统可以作为课设、毕设使用,也可以单独使用项目的SSM框架。
系统介绍
该系统实现一个B/S架构、自定义高亮显示方案的多文本编辑器,主要包括文档编辑,编辑器设置,插件管理三个模块,主要功能是对文档的添加修改,对文档进行样式的选定,以及对编辑器插件的管理。
相关技术
系统后台使用SSM核心技术框架,数据库为MySql,前端页面集成JQuery+Bootstrap实现。部署简单,tomcat容器即可。
系统设计
对于系统应用者,即系统的访问者来说,我们采用B/S的接入方式,可以进行文档的编辑、删除、分享等操作,并且为他们提供个性化的内容与服务。
架构模型
本系统采用:模型—视图—控制器(Model-View-Controller,MVC)处理模型。
- 模型架构
- 处理流程
功能模块
主要实现了文档管理、编辑器设置、插件管理、用户管理,登录/登出等功能模块。具体模块划分见业务模块图:
系统截图
- 登录界面
- 文档管理
- 文档编辑/编辑器设置
- 插件管理
- 用户管理
部分源码
代码结构
主要代码
- 用户管理API
package com.smwx.controller;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.smwx.domain.TUser;
import com.smwx.service.IUserService;
import com.smwx.utils.PageBean;
@Controller
@RequestMapping("user")
public class UserController {
@Autowired
private IUserService iUserService;
/**
* 用户管理列表
* @author lzj
* @return
*/
@RequestMapping("index")
public String index(ModelMap mp,PageBean pageBean){
pageBean = iUserService.findByPageBean(pageBean);
mp.put("pageBean", pageBean);
return "jsp/sys/user_index";
}
/**
* 根据id删除一条求用户记录
* @author lzj
* @param id
* @return
*/
@RequestMapping("deleteUser")
@ResponseBody
public Boolean deleteDocType(String id ){
boolean bool = iUserService.deleteUser(Integer.parseInt(id));
return bool;
}
/**
* @description: 编辑用户时回显用户信息
* @author lzj
* @date 2018年3月19日 下午10:30:25
* @return String
*/
@RequestMapping("viewUser")
@ResponseBody
public TUser viewUser(String id){
TUser user = iUserService.findById(Integer.parseInt(id));
return user;
}
/**
* @description: 更新用户记录
* @author lzj
* @date 2018年3月20日 上午10:00:02
* @return boolean
*/
@RequestMapping("updateUser")
@ResponseBody
public boolean updateUser(TUser tUser){
boolean result = iUserService.updateUser(tUser);
if(result){
return true;
}else{
return false;
}
}
/**
* 验证账号是否重复
* @description: 更新用户记录
* @author lzj
* @return boolean
*/
@RequestMapping("findIsReAccouont")
@ResponseBody
public boolean findIsReAccouont(String account){
boolean bool = iUserService.findIsReAccouont(account);
return bool;
}
/**
* 保存注册用户
* @description: 更新用户记录
* @author lzj
* @return boolean
*/
@RequestMapping("saveUser")
@ResponseBody
public boolean saveUser(TUser tuser){
boolean bool = iUserService.saveUser(tuser);
return bool;
}
/**
* 登陆
* @author lzj
* @return
*/
@RequestMapping("loginOn")
@ResponseBody
public boolean loginOn(TUser tuser,HttpServletRequest request){
boolean bool = iUserService.loginOn(tuser,request);
return bool;
}
}
- 文档编辑
package com.smwx.controller;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.google.gson.Gson;
import com.smwx.domain.DDoc;
import com.smwx.service.IDocService;
import com.smwx.service.IEdSetService;
import com.smwx.vo.TreeVo;
/**
* 编辑器设置控制层
* @author lzj
*
*/
@Controller
@RequestMapping("edset")
public class EdSetController {
@Autowired
private IEdSetService edSetService;
@Autowired
private IDocService docService;
/**
* 编辑器主页面
* @author lzj
* @param mp
* @return
*/
@RequestMapping("index")
public String index(ModelMap mp){
TreeVo treeVo = edSetService.findTreeAll();
mp.put("treeVo", new Gson().toJson(treeVo));
return "jsp/ed/ed_index";
}
/**
* 根据文档和文档类型
* 查询对应的编辑器和文档内容
* @author lzj
* @return
*/
@RequestMapping("findByDocAndEd")
@ResponseBody
public DDoc findByDocAndEd(Integer docTypeId,Integer docId){
DDoc doc = edSetService.findByDocAndEd(docTypeId,docId);
return doc;
}
/**
*
* @author lzj
* @return
*/
@RequestMapping("saveEdSet")
@ResponseBody
public boolean saveEdSet(DDoc doc,HttpServletRequest request){
boolean bool = docService.updateDoc(doc, request);
return bool;
}
}
- 插件管理
package com.smwx.controller;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.google.gson.Gson;
import com.smwx.domain.DDocType;
import com.smwx.domain.DDocTypePlug;
import com.smwx.domain.DPlugIn;
import com.smwx.service.IDocTypePlugService;
import com.smwx.service.IDocTypeService;
import com.smwx.service.IPlugInService;
import com.smwx.utils.PageBean;
@Controller
@RequestMapping("pi")
public class PlugInController {
@Autowired
private IPlugInService iPlugInService;
@Autowired
private IDocTypeService iDocTypeService;
@Autowired
private IDocTypePlugService iDocTypePlugService;
/**
* @description 插件列表
* @author lzj
* @date 2018年3月22日 上午11:35:15
* @return String
*/
@RequestMapping("index")
public String index(ModelMap mp,PageBean pageBean){
pageBean = iPlugInService.findByPageBean(pageBean);
mp.put("pageBean", pageBean);
return "jsp/pi/pi_index";
}
/**
* @description 插件安装请求,首次页面访问
* @author lzj
* @date 2018年3月24日 下午2:44:23
* @return String
*/
@RequestMapping("grant")
public String grant(ModelMap mp,PageBean pageBean, String id){
//存放系统中所有文档类型集合
List<DDocType> typeList = new ArrayList<>();
//存放指定文档类型关联的插件
List<DPlugIn> plugList = new ArrayList<>();
//查询所有的文档类型
typeList = iDocTypeService.findAll();
//查询到所有的内置插件
pageBean = iPlugInService.findByPageBean(pageBean);
List<DPlugIn> content = new ArrayList<>();
//获取插件分页列表
content = (List<DPlugIn>) pageBean.getContent();
//插件类型ID为空时,首次进入该页面
if(id == null){
plugList = iPlugInService.findByDocType(typeList.get(0).getDocTypeId());
}else{//插件类型ID为不为空时
plugList = iPlugInService.findByDocType(Integer.valueOf(id));
for(int i=0; i<typeList.size(); i++){
if(typeList.get(i).getDocTypeId() == Integer.valueOf(id)){
typeList.get(i).setIsSelected("yes");
}
}
}
for(int i=0; i<plugList.size();i++){
for(int j=0; j<content.size(); j++){
if(plugList.get(i).getPlugInId() == content.get(j).getPlugInId() ){
content.get(j).setIsChecked("yes");
}
}
}
pageBean.setContent(content);
mp.put("pageBean", pageBean);
mp.put("docTypes", typeList);
return "jsp/pi/pi_grant";
}
/**
* @description 插件安装请求,通过选择文档类型时,请求插件列表
* @author lzj
* @date 2018年3月29日 下午9:01:08
* @return Map<String,Object>
*/
@RequestMapping("grantWith")
@ResponseBody
public Map<String, Object> grantWith(PageBean pageBean, String id){
//存放系统中所有文档类型集合
List<DDocType> typeList = new ArrayList<>();
//存放指定文档类型关联的插件
List<DPlugIn> plugList = new ArrayList<>();
//查询所有的文档类型
typeList = iDocTypeService.findAll();
//查询到所有的内置插件
pageBean = iPlugInService.findByPageBean(pageBean);
List<DPlugIn> content = new ArrayList<>();
//获取插件分页列表
content = (List<DPlugIn>) pageBean.getContent();
plugList = iPlugInService.findByDocType(Integer.valueOf(id));
for(int i=0; i<typeList.size(); i++){
if(typeList.get(i).getDocTypeId() == Integer.valueOf(id)){
typeList.get(i).setIsSelected("yes");
}
}
for(int i=0; i<plugList.size();i++){
for(int j=0; j<content.size(); j++){
if(plugList.get(i).getPlugInId() == content.get(j).getPlugInId() ){
content.get(j).setIsChecked("yes");
}
}
}
pageBean.setContent(content);
Map<String, Object> map = new HashMap<>();
map.put("pageBean", pageBean);
map.put("docTypes", typeList);
Gson gson = new Gson();
return map;
}
/**
* @description 保存插件记录
* @author lzj
* @date 2018年3月22日 下午1:26:05
* @return boolean
*/
@RequestMapping("savePlugIn")
@ResponseBody
public boolean savePlugIn(DPlugIn dPlugIn){
boolean bool = iPlugInService.savePlugIn(dPlugIn);
return bool;
}
/**
* @description 根据id删除指定的插件
* @author lzj
* @date 2018年3月22日 下午1:40:32
* @return boolean
*/
@RequestMapping("deletePlugIn")
@ResponseBody
public boolean deletePlugIn(String id){
boolean bool = iPlugInService.deletePlugIn(Integer.valueOf(id));
return bool;
}
/**
* @description 安装插件
* @author lzj
* @date 2018年4月1日 上午9:58:16
* @return boolean
*/
@RequestMapping("install")
@ResponseBody
public boolean install(DDocTypePlug dDocTypePlug){
boolean bool = iDocTypePlugService.saveDocTypePlug(dDocTypePlug);
return bool;
}
/**
* @description 卸载文档类型指定的插件
* @author lzj
* @date 2018年4月1日 上午10:02:43
* @return String
*/
@RequestMapping("unInstall")
@ResponseBody
public String unInstall(DDocTypePlug dDocTypePlug){
boolean bool = iDocTypePlugService.deleteByDocTypeAndPlugIn(dDocTypePlug);
if(bool){//卸载成功
return "success";
}else{//卸载失败,插件未安装
return "not exist";
}
}
}
- 登录页面
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
+ path + "/";
%>
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<!-- Meta, title, CSS, favicons, etc. -->
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>文档管理系统</title>
<!-- Bootstrap -->
<link href="css/bootstrap.min.css" rel="stylesheet">
<!-- Font Awesome -->
<link href="css/font-awesome.min.css" rel="stylesheet">
<!-- NProgress -->
<link href="css/nprogress.css" rel="stylesheet">
<!-- Animate.css -->
<link href="css/animate.min.css" rel="stylesheet">
<!-- Custom Theme Style -->
<link href="css/custom.min.css" rel="stylesheet">
</head>
<body class="login">
<div>
<a class="hiddenanchor" id="signup"></a>
<a class="hiddenanchor" id="signin"></a>
<div class="login_wrapper">
<div class="animate form login_form">
<section class="login_content">
<form>
<h1>Welcome Login</h1>
<div>
<input id="loginAcc" type="text" class="form-control" placeholder="Username" required="" />
</div>
<div>
<input id="loginPass" type="password" class="form-control" placeholder="Password" required="" />
</div>
<div>
<a id="login" class="btn btn-default submit" href="javaScript:void(0)">Log in</a>
<a class="reset_pass" href="#">Lost your password?</a>
</div>
<div class="clearfix"></div>
<div class="separator">
<p class="change_link">New to site?
<a href="#signup" class="to_register"> Create Account </a>
</p>
<div class="clearfix"></div>
<br />
<div>
<h1><i class="fa fa-paw"></i> North University of China!</h1>
<p>©2018 Code2Life. Software School of North University of China</p>
</div>
</div>
</form>
</section>
</div>
<div id="register" class="animate form registration_form">
<section class="login_content">
<form id="createAccont">
<h1>Create Account</h1>
<div>
<input id="createAcc" type="text" class="form-control" placeholder="Account" required="" />
</div>
<div>
<input id="createPass" type="password" class="form-control" placeholder="Password" required="" />
</div>
<div>
<input id="createPassAgain" type="password" class="form-control" placeholder="Password again" required="" />
</div>
<div>
<input id="createUser" type="text" class="form-control" placeholder="Username" required="" />
</div>
<div>
<input id="createTele" type="number" class="form-control" placeholder="Telephone" required="" />
</div>
<div>
<a id="submit" class="btn btn-default submit" href="javaScript:void(0)">Submit</a>
</div>
<div class="clearfix"></div>
<div class="separator">
<p class="change_link">Already a member ?
<a href="#signin" class="to_register"> Log in </a>
</p>
<div class="clearfix"></div>
<br />
<div>
<h1><i class="fa fa-paw"></i> North University of China!</h1>
<p>©2018 lzj. Software School of North University of China</p>
</div>
</div>
</form>
</section>
</div>
</div>
</div>
<!-- jQuery -->
<script src="js/jquery.min.js"></script>
<script src="js/layer/layer.js"></script>
<script type="text/javascript">
//登陆
$("#login").click(function(){
if(''!=$("#loginAcc").val().trim() && ''!=$("#loginPass").val().trim()){
$.ajax({
type : "POST",
url : "user/loginOn.do",
data : getParam('login'),
dataType : "json",
success : function(result) {
if(result){
window.location.href="menu/home.do";
}else{
layer.alert("登录名或密码错误!",{icon:2});
}
}
})
}else{
layer.msg("账号密码不能为空!",{icon:2})
}
})
//创建用户
$("#submit").click(function(){
var obj = verification();
if(obj.flag){
layer.msg(obj.msg,{icon:2})
}else{
$.ajax({
type : "POST",
url : "user/saveUser.do",
data : getParam('create'),
dataType : "json",
success : function(result) {
if(result){
layer.msg("创建成功!",{icon:1});
setTimeout(function () {
window.location.href="login.do#signin";
}, 500);
}else{
layer.msg("创建失败!",{icon:2});
}
}
})
}
})
//创建用户验证
function verification(){
var flag = false,msg='';
if(!flag){
$("#createAccont").find("input").each(function(){
if(''==$(this).val().trim()){
flag = true;
msg = "请将信息填写完整!";
return false;
}
})
}
if(!flag){
if($("#createPass").val().trim()!=$("#createPassAgain").val().trim()){
flag = true;
msg = "两次密码不一致,请重新输入!";
}
}
if(!flag){
var account = $("#createAcc").val().trim();
$.ajax({
type : "POST",
url : "user/findIsReAccouont.do",
data : "account="+account,
async:false,
dataType : "json",
success : function(result) {
if(result){
flag = true;
msg = "账号重复请重新输入!";
}
}
})
}
return {flag:flag,msg:msg};
}
//获取填写信息
function getParam(result){
var longinParam = {
userNum:$("#loginAcc").val(),
password:$("#loginPass").val()
}
var createParam = {
userName:$("#createUser").val(),
userNum:$("#createAcc").val(),
password:$("#createPass").val(),
userContact:$("#createTele").val(),
}
if('login'==result){
return longinParam;
}else if('create'==result){
return createParam;
}
}
</script>
</body>
</html>
最后
这个系统本人自己开发,实现了基本的富文本编辑功能,可以供学习课设、毕设题目参考使用,后期根据需要还可以继续完善扩展。感兴趣可扫码关注咨询
