在线文档管理系统项目文档

1. 项目简介

在线文档管理系统是一个基于Spring Boot框架开发的企业级文档管理平台,旨在为企业提供高效的文档存储、管理和共享解决方案。系统采用B/S架构,实现了文档的上传、下载、分类管理、权限控制等功能,同时集成了公告发布、部门管理、员工管理等辅助功能,为企业内部文档流转提供了完整的解决方案。

该系统主要功能模块包括:

  • 文档管理:支持多种格式文档的上传、下载、分类和检索
  • 公告管理:发布企业公告信息
  • 部门管理:维护企业部门架构信息
  • 岗位管理:定义企业岗位信息
  • 员工管理:管理员工基本信息及权限
  • 系统管理:配置系统参数和用户权限

系统采用前后端分离架构,前端使用Vue.js+Element UI,后端采用Spring Boot+MyBatis Plus,数据库支持MySQL和SQL Server,具有良好的扩展性和跨平台特性。

2. 技术栈

2.1 后端技术

  • 核心框架:Spring Boot 2.2.2.RELEASE
  • 持久层:MyBatis Plus 2.3
  • 数据库:MySQL 5.7 / SQL Server
  • 安全框架:Apache Shiro 1.3.2
  • 工具类库
    • Hutool 4.0.12(Java工具包)
    • Fastjson 1.2.8(JSON处理)
    • Commons-lang3 3.0(常用工具)
    • Commons-io 2.5(IO操作)
  • 其他依赖
    • Protobuf 3.10.0(协议缓冲)

2.2 前端技术

  • 基础框架:Vue.js
  • UI组件库:Element UI
  • 图表库:ECharts
  • 地图组件:Vue AMap
  • 工具库
    • axios(HTTP请求)
    • js-md5(MD5加密)
    • print-js(打印功能)
    • vue-json-excel(Excel导出)

2.3 开发工具

  • IDE:IntelliJ IDEA
  • 构建工具:Maven 3.6+
  • 版本控制:Git
  • 数据库工具:Navicat/SQLyog

3. 详细介绍

3.1 系统架构设计

系统采用经典的三层架构设计:

  1. 表现层:基于Vue.js的前端界面,负责用户交互和数据显示
  2. 业务逻辑层:Spring Boot后端服务,处理业务逻辑和权限控制
  3. 数据访问层:MyBatis Plus实现数据库操作,支持多种数据库

3.2 核心功能模块

3.2.1 文档管理模块
  • 文档上传:支持多种格式文档上传(Word、Excel、PPT等)
  • 文档分类:按类型对文档进行分类管理
  • 文档检索:支持按名称、类型等条件检索文档
  • 文档下载:提供文档下载功能,支持权限控制
  • 文档统计:统计文档数量、下载次数等数据
3.2.2 公告管理模块
  • 公告发布:管理员可发布企业公告
  • 公告浏览:员工可查看与自己相关的公告
  • 公告分类:按部门、岗位等维度分类展示公告
3.2.3 组织架构管理
  • 部门管理:维护企业部门信息,包括部门人数、组织架构图等
  • 岗位管理:定义企业岗位信息
  • 员工管理:维护员工基本信息,关联部门和岗位
3.2.4 权限控制系统
  • 基于角色的访问控制(RBAC)
  • 细粒度的功能权限控制
  • 数据权限控制(部门隔离)
  • Token机制实现无状态认证

3.3 数据库设计

系统主要数据表包括:

  • wendangxinxi(文档信息表)
  • gonggaoxinxi(公告信息表)
  • bumenxinxi(部门信息表)
  • gangwei(岗位表)
  • yuangong(员工表)
  • users(系统用户表)
  • token(Token表)
  • config(系统配置表)

4. 部分代码

4.1 文档管理控制器

@RestController
@RequestMapping("/wendangxinxi")
public class WendangxinxiController {
    @Autowired
    private WendangxinxiService wendangxinxiService;

    /**
     * 后端列表
     */
    @RequestMapping("/page")
    public R page(@RequestParam Map<String, Object> params,WendangxinxiEntity wendangxinxi,
        HttpServletRequest request){
        EntityWrapper<WendangxinxiEntity> ew = new EntityWrapper<WendangxinxiEntity>();
        PageUtils page = wendangxinxiService.queryPage(params, 
            MPUtil.sort(MPUtil.between(MPUtil.likeOrEq(ew, wendangxinxi), params), params));
        return R.ok().put("data", page);
    }
    
    /**
     * 前端列表
     */
    @RequestMapping("/list")
    public R list(@RequestParam Map<String, Object> params,WendangxinxiEntity wendangxinxi, 
        HttpServletRequest request){
        EntityWrapper<WendangxinxiEntity> ew = new EntityWrapper<WendangxinxiEntity>();
        PageUtils page = wendangxinxiService.queryPage(params, 
            MPUtil.sort(MPUtil.between(MPUtil.likeOrEq(ew, wendangxinxi), params), params));
        return R.ok().put("data", page);
    }

    /**
     * 后端保存
     */
    @RequestMapping("/save")
    public R save(@RequestBody WendangxinxiEntity wendangxinxi, HttpServletRequest request){
        wendangxinxi.setId(new Date().getTime()+new Double(Math.floor(Math.random()*1000)).longValue());
        wendangxinxiService.insert(wendangxinxi);
        return R.ok();
    }
    
    /**
     * 删除
     */
    @RequestMapping("/delete")
    public R delete(@RequestBody Long[] ids){
        wendangxinxiService.deleteBatchIds(Arrays.asList(ids));
        return R.ok();
    }
}

4.2 权限拦截器

@Component
public class AuthorizationInterceptor implements HandlerInterceptor {
    public static final String LOGIN_TOKEN_KEY = "Token";

    @Autowired
    private TokenService tokenService;
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, 
        Object handler) throws Exception {

        //支持跨域请求
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Headers", "x-requested-with,request-source,Token, Origin,imgType, Content-Type, cache-control,postman-token,Cookie, Accept,authorization");
        response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
    
        // 跨域时会首先发送一个OPTIONS请求
        if (request.getMethod().equals(RequestMethod.OPTIONS.name())) {
            response.setStatus(HttpStatus.OK.value());
            return false;
        }
        
        IgnoreAuth annotation;
        if (handler instanceof HandlerMethod) {
            annotation = ((HandlerMethod) handler).getMethodAnnotation(IgnoreAuth.class);
        } else {
            return true;
        }

        //从header中获取token
        String token = request.getHeader(LOGIN_TOKEN_KEY);
        
        //不需要验证权限的方法直接放过
        if(annotation!=null) {
            return true;
        }
        
        TokenEntity tokenEntity = null;
        if(StringUtils.isNotBlank(token)) {
            tokenEntity = tokenService.getTokenEntity(token);
        }
        
        if(tokenEntity != null) {
            request.getSession().setAttribute("userId", tokenEntity.getUserid());
            request.getSession().setAttribute("role", tokenEntity.getRole());
            request.getSession().setAttribute("tableName", tokenEntity.getTablename());
            request.getSession().setAttribute("username", tokenEntity.getUsername());
            return true;
        }
        
        PrintWriter writer = null;
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        try {
            writer = response.getWriter();
            writer.print(JSONObject.toJSONString(R.error(401, "请先登录")));
        } finally {
            if(writer != null){
                writer.close();
            }
        }
        return false;
    }
}

4.3 文件上传控制器

@RestController
@RequestMapping("file")
@SuppressWarnings({"unchecked","rawtypes"})
public class FileController{
    @Autowired
    private ConfigService configService;
    
    /**
     * 上传文件
     */
    @RequestMapping("/upload")
    public R upload(@RequestParam("file") MultipartFile file,String type) throws Exception {
        if (file.isEmpty()) {
            throw new EIException("上传文件不能为空");
        }
        String fileExt = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".")+1);
        File path = new File(ResourceUtils.getURL("classpath:static").getPath());
        if(!path.exists()) {
            path = new File("");
        }
        File upload = new File(path.getAbsolutePath(),"/upload/");
        if(!upload.exists()) {
            upload.mkdirs();
        }
        String fileName = new Date().getTime()+"."+fileExt;
        File dest = new File(upload.getAbsolutePath()+"/"+fileName);
        file.transferTo(dest);
        if(StringUtils.isNotBlank(type) && type.equals("1")) {
            ConfigEntity configEntity = configService.selectOne(new EntityWrapper<ConfigEntity>().eq("name", "faceFile"));
            if(configEntity==null) {
                configEntity = new ConfigEntity();
                configEntity.setName("faceFile");
                configEntity.setValue(fileName);
            } else {
                configEntity.setValue(fileName);
            }
            configService.insertOrUpdate(configEntity);
        }
        return R.ok().put("file", fileName);
    }
    
    /**
     * 下载文件
     */
    @IgnoreAuth
    @RequestMapping("/download")
    public ResponseEntity<byte[]> download(@RequestParam String fileName) {
        try {
            File path = new File(ResourceUtils.getURL("classpath:static").getPath());
            if(!path.exists()) {
                path = new File("");
            }
            File upload = new File(path.getAbsolutePath(),"/upload/");
            if(!upload.exists()) {
                upload.mkdirs();
            }
            File file = new File(upload.getAbsolutePath()+"/"+fileName);
            if(file.exists()){
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);    
                headers.setContentDispositionFormData("attachment", fileName);    
                return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),headers, HttpStatus.CREATED);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new ResponseEntity<byte[]>(HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

5. 部分截图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6. 项目总结

在线文档管理系统基于Spring Boot+Vue.js技术栈开发,实现了企业文档管理的核心功能,具有以下特点:

  1. 技术先进:采用主流的前后端分离架构,使用现代化的开发框架和工具,保证了系统的可维护性和扩展性。
  2. 功能完善:不仅实现了文档管理的基本功能,还提供了公告发布、组织架构管理等辅助功能,满足企业日常办公需求。
  3. 安全可靠:基于Shiro框架实现了完善的权限控制系统,确保数据安全和操作合规。
  4. 用户体验良好:采用Element UI构建用户界面,操作简单直观,响应速度快。
  5. 扩展性强:系统架构设计合理,模块划分清晰,便于后续功能扩展和定制开发。

在实际应用中,该系统可以显著提高企业文档管理效率,减少纸质文档使用,实现文档的电子化、规范化管理。未来可以考虑增加以下功能:

  • 文档版本控制
  • 在线协作编辑
  • 全文检索功能
  • 移动端适配
  • 与OA系统集成

总体来说,该项目是一个功能完善、技术先进的文档管理解决方案,适用于各类企事业单位的文档管理需求。

在线演示:
后台:http://springbootpkh49.xiaobias.com/springbootpkh49/admin/dist/index.html
管理员:abo/abo
资源:https://fifteen.xiaobias.com/source/41

Logo

惟楚有才,于斯为盛。欢迎来到长沙!!! 茶颜悦色、臭豆腐、CSDN和你一个都不能少~

更多推荐