仰望星空——冲刺日志Day5

Part1 各个成员今日完成的任务

  •  20211302:继续开发公文传输功能,实现公文的查看和编辑。
  •  20211304:完善权限表,实现细粒度的权限控制。
  •  20211308:继续处理用户管理功能的反馈,确保稳定性。
  •  20211317:继续开发日志记录功能,记录更多的操作信息。
  •  20211318:完成国密算法的集成和性能优化。

公文的查看和编辑功能:

控制器:ArticleController.java

package cn.edu.nuc.article.controller;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

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

import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import cn.edu.nuc.article.dto.TreeDto;
import cn.edu.nuc.article.entity.Article;
import cn.edu.nuc.article.entity.Attachment;
import cn.edu.nuc.article.entity.AuditMessage;
import cn.edu.nuc.article.entity.Log;
import cn.edu.nuc.article.entity.User;
import cn.edu.nuc.article.service.ArticleService;
import cn.edu.nuc.article.service.AttachmentService;
import cn.edu.nuc.article.service.AuditMessageService;
import cn.edu.nuc.article.service.FileService;
import cn.edu.nuc.article.service.LogService;
import cn.edu.nuc.article.service.ReceiveService;
import cn.edu.nuc.article.service.UserService;
import cn.edu.nuc.article.util.IpUtil;

/**
 * 公文Controller
 * @author 仰望星空
 *
 */
@Controller
@RequestMapping("/article")
public class ArticleController {

    /**
     * 公文Service
     */
    @Autowired
    private ArticleService articleService;
    
    /**
     * 用户Service
     */
    @Autowired
    private UserService userService;
    
    /**
     * 文件服务
     */
    @Autowired
    private FileService fileService;
    
    /**
     * 公文接收Service
     */
    @Autowired
    private ReceiveService receiveService;
    
    /**
     * 附件Service
     */
    @Autowired
    private AttachmentService attachmentService;
    
    /**
     * 公文审核信息Service
     */
    @Autowired
    private AuditMessageService auditMessageService;
    
    /**
     * 日志Service
     */
    @Autowired
    private LogService logService;
    
    /**
     * Activiti运行时Service,用于启动流程
     */
    @Autowired
    private RuntimeService runtimeService;
    
    /**
     * Activiti任务Service,查询待办任务和完成任务
     */
    @Autowired
    private TaskService taskService;
    
    /**
     * 公文修改(撰稿)
     * @return
     */
    @RequestMapping("/modifyArticle")
    @Transactional
    public String modifyArticle(Map<String, Object> map, HttpSession session ,
            String title, Integer articleId, Integer[] received, Integer auditor, 
            String taskId,
            @RequestParam(name= "doc", required = false) MultipartFile doc,
            @RequestParam(name= "attachment", required = false) MultipartFile[] attachment) {
        
        try {
            //1.首先检查必填项是否都填写正确
            
            if (validateForm(map, articleId, title, received, auditor, doc) == false) {
                return "forward:/article/toModify";
            }
            
            //2.设置公文相关参数并新增公文
            Article article = new Article();
            article.setArticleid(articleId);
            article.setArticlestate(0); //0表示审核中
            article.setTitle(title);
            
            //撰稿人、审稿人、发布时间在公文撰稿时已经设置过,不需要也不能改
            
            //判断操作结果是否成功
            if (!articleService.modifyArticle(article)) {
                map.put("msg", "系统出现错误,在修改公文信息时操作失败!");
                map.put("result", false);
                return "forward:/article/toModify";
            }
            
            //拿到修改后的公文信息
            User user = (User) session.getAttribute("user");
            article = articleService.getArticleById(articleId, user.getUserid());

            //3 删除旧的接收关系,再添加信息
            
            //3.1 删除旧的接收关系
            if (receiveService.deleteReceive(articleId)) {
                
                //3.2 添加新的接收人信息
                for (Integer receiverId : received) {
                    
                    if (!receiveService.addReceive(articleId, receiverId)) {
                        map.put("msg", "系统出现错误,在修改公文接收人信息时操作失败!");
                        map.put("result", false);
                        return "forward:/article/toModify";
                    }
                }
                
            } else {
                map.put("msg", "系统出现错误,在修改公文接收人信息时操作失败!");
                map.put("result", false);
                return "forward:/article/toModify";
            }

            //4. 看一下公文原文是否需要更新,如果需要则更新之
            if (doc != null && doc.getSize() != 0) {
                
                //4.1 删掉旧的公文原文信息
                Attachment target = null;
                for (Attachment attachment2 : article.getAttachments()) {
                    if (attachment2.getAttachtype() == 0) { //正文
                        target = attachment2;
                    }
                }
                
                boolean result = attachmentService.deleteAttachment(target.getAttachmentid());
                
                if (result == true) {
                    
                    //4.2 调用FileService,使用JackRabbit保存新的公文电子文档
                    String fileId = fileService.save(doc.getInputStream());
                    
                    //4.3 拼装出公文原文的附件信息
                    Attachment articleDocument = new Attachment();
                    articleDocument.setArticleId(article.getArticleid());
                    articleDocument.setAttachtype(0); //0表示正文
                    articleDocument.setFilename(doc.getOriginalFilename());
                    articleDocument.setMimetype(doc.getContentType());
                    articleDocument.setUploadtime(new Date());
                    articleDocument.setFilesize(doc.getSize());
                    articleDocument.setFileid(fileId); //JackRabbit返回的FileId
                    
                    //4.4 添加信息到附件表
                    if (!attachmentService.addAttachment(articleDocument)) {
                        map.put("msg", "系统出现错误,在添加公文附件时操作失败!");
                        map.put("result", false);
                        return "forward:/article/toModify";
                    }
                } else {
                    map.put("msg", "系统出现错误,在删除公文旧附件时操作失败!");
                    map.put("result", false);
                    return "forward:/article/toModify";
                }
            }

            //5.如果用户上传了附件,就要做对应更新
            if (attachment != null && attachment.length != 0 && attachment[0].getSize() != 0) {
                
                //5.1 删掉公文旧附件
                for (Attachment attachment2 : article.getAttachments()) {
                    if (attachment2.getAttachtype() != 0) { //附件
                        attachmentService.deleteAttachment(attachment2.getAttachmentid());
                    }
                }
                
                //5.2 上传新附件
                for (MultipartFile attachFile : attachment) {
                    
                    //5.2.1 调用FileService,使用JackRabbit保存公文附件
                    String attfileId = fileService.save(attachFile.getInputStream());
                    
                    //5.2.2 拼装附件信息
                    Attachment attch = new Attachment();
                    attch.setArticleId(article.getArticleid());
                    attch.setAttachtype(1); //1表示附件
                    attch.setFileid(attfileId);
                    attch.setFilename(attachFile.getOriginalFilename());
                    attch.setFilesize(attachFile.getSize());
                    attch.setMimetype(attachFile.getContentType());
                    attch.setUploadtime(new Date());
                    
                    //5.2.3 添加信息到附件表
                    if (!attachmentService.addAttachment(attch)) {
                        map.put("msg", "系统出现错误,在修改公文附件时操作失败!");
                        map.put("result", false);
                        return "forward:/article/toModify";
                    }
                    
                }
            }
            
            //6.完成公文修改的待办任务,使其转向公文审核任务
            
            //6.1 完成选择,使其转向修改公文任务
            Map<String, Object> variables = new HashMap<>();
            variables.put("decision", true);
            
            taskService.complete(taskId, variables);
            
            //6.2 根据流程实例和办理人查询待办,得到修改公文任务的TaskId,然后完成该任务
            Task task = taskService.createTaskQuery()
                    .taskAssignee(user.getUserid().toString())
                    .processInstanceId(article.getProcessinstanceId())
                    .singleResult();
            
            taskService.complete(task.getId());

            //7.如果以上操作都没有问题,那就是成功了
            map.put("msg", "公文[" + article.getTitle() + "]上传成功,请耐心等待审核!");
            map.put("result", true);
            
            //返回等待审核结果界面
            return "forward:/article/toAduitResult";
        } catch (Exception e) {
            System.out.println("公文修改出错!");
            e.printStackTrace();
            
            map.put("msg", "系统出现严重错误,公文修改操作失败!");
            map.put("result", false);
            return "forward:/article/toModfiy";
        }
    }
    
    /**
     * 进入公文修改界面
     * @return
     * @throws Exception 
     */
    @RequestMapping("/toModfiy")
    public String toModify(HttpSession session, Map<String, Object> map,
            Integer articleId, String taskId) throws Exception {
        
        //加载出该用户所在机构所有审稿人姓名
        
        //1 从Session中取出User
        User user = (User) session.getAttribute("user");
        
        //2 通过用户得到其所在机构的id
        Integer instid = user.getInstId();
        
        //3 得到该机构所有未被禁用的审核人员的信息
        List<User> auditors = userService.findValidAuditor(instid);
        
        //4 得到公文信息
        Article article = articleService.getArticleById(articleId, user.getUserid());

        //5 保存为备选项
        map.put("auditors", auditors);
        map.put("article", article);
        map.put("taskId", taskId);
        
        return "article/articlemodify";
    }
    
    /**
     * 通过Ajax方式获得联系人树(修改)
     * @return
     * @throws Exception
     */
    @ResponseBody
    @RequestMapping("/getTreeModify")
    public List<TreeDto> getTreeModify(HttpSession session, Integer articleId)
            throws Exception {
        
        User user = (User) session.getAttribute("user");
        
        List<TreeDto> dtos = new ArrayList<>();
        dtos.add(articleService.getTreeDTOJSON(articleId, user.getUserid()));
        return dtos;
    }
    
    /**
     * 用户选择删除公文
     * @param map
     * @return
     */
    @RequestMapping("/deleteArticle")
    public String deleteArticle(Map<String, Object> map, Integer articleId, String taskId) {
        
        //设置公文状态为被删除
        Article article = new Article();
        article.setArticleid(articleId);
        article.setArticlestate(4);
        
        if (articleService.modifyArticle(article)) {
            
            Map<String, Object> variables = new HashMap<>();
            variables.put("decision", false);
            
            taskService.complete(taskId, variables);
            
            map.put("msg", "删除公文成功");
            map.put("result", true);
        } else {
            map.put("msg", "删除公文失败");
            map.put("result", false);
        }

        return "forward:/article/toAduitResult";
    }
    
    /**
     * 按id加载公文接收信息
     * @return
     */
    @RequestMapping("/findByIdHistory")
    public String findByIdHistory(Map<String, Object> map, HttpSession session,
                HttpServletRequest request, Integer articleId) {
        
        //1.从Session中获得User,取得其UserId
        User user = (User) session.getAttribute("user");
        Integer userId = user.getUserid();
        
        //2.向日志表插入一条日志记录
        Log log = new Log();
        log.setBussinessId(articleId);
        log.setIpaddress(IpUtil.getRequestRealIp(request)); //获取ip地址
        log.setOperatorId(userId);
        log.setOptname("查看公文");
        log.setOpttime(new Date());
        logService.addLog(log);
        
        //3.检查访问权限
        if (articleService.isArticleAvaliable(articleId, userId) == true) {
            Article article = articleService.getArticleById(articleId, userId); 
            
            //4.保存查询结果
            map.put("article", article);
            return "article/articleDetail";
        } else {
            map.put("msg", "您没有查看公文的权限!");
            map.put("result", false);
            return "forward:/article/getMyHistoryList";
        }
    }
    
    /**
     * 查询接收公文信息
     * @param map
     * @param session
     * @param keyword
     * @return
     */
    @RequestMapping("/getMyHistoryList")
    public String getMyHistoryList(Map<String, Object> map, HttpSession session,
            @RequestParam(value="keyword", required=false) String keyword) {

        //找出当前登录用户
        User user = (User) session.getAttribute("user");
        
        //设置查询条件
        Article article = new Article();
        article.setUserId(user.getUserid());
        
        if (StringUtils.hasText(keyword)) { //用户指定了查询关键字
            article.setTitle(keyword);
        }

        List<Article> articles = articleService.getMyArticleList(article);

        //保存结果集带到页面显示
        map.put("articles", articles);
        
        //保存模糊查询条件以便回显
        map.put("keyword", keyword);
        
        return "article/articleHistoryManage";
    }
    
    /**
     * 按id加载公文接收信息
     * @return
     */
    @RequestMapping("/findByIdReceive")
    public String findByIdReceive(Map<String, Object> map, HttpSession session,
                HttpServletRequest request, Integer articleId) {
        
        //1.从Session中获得User,取得其UserId
        User user = (User) session.getAttribute("user");
        Integer userId = user.getUserid();
        
        //2.向日志表插入一条日志记录
        Log log = new Log();
        log.setBussinessId(articleId);
        log.setIpaddress(IpUtil.getRequestRealIp(request)); //获取ip地址
        log.setOperatorId(userId);
        log.setOptname("查看公文");
        log.setOpttime(new Date());
        logService.addLog(log);
        
        //3.检查访问权限
        if (articleService.isArticleAvaliable(articleId, userId) == true) {
            Article article = articleService.getArticleById(articleId, userId); 
            
            //4.保存查询结果
            map.put("article", article);
            return "article/articleDetail";
        } else {
            map.put("msg", "您没有查看公文的权限!");
            map.put("result", false);
            return "forward:/article/getMyReceiveList";
        }
    }
    
    /**
     * 查询接收公文信息
     * @param map
     * @param session
     * @param keyword
     * @return
     */
    @RequestMapping("/getMyReceiveList")
    public String getMyReceiveList(Map<String, Object> map, HttpSession session,
            @RequestParam(value="keyword", required=false) String keyword) {
        
        //找出当前登录用户
        User user = (User) session.getAttribute("user");
        
        //设置查询条件
        Article article = new Article();
        article.setArticlestate(3);
        article.setUserId(user.getUserid());
        
        if (StringUtils.hasText(keyword)) { //用户指定了查询关键字
            article.setTitle(keyword);
        }
        
        List<Article> articles = articleService.getMyArticles(article);
        
        //保存结果集带到页面显示
        map.put("articles", articles);
        
        //保存模糊查询条件以便回显
        map.put("keyword", keyword);
        
        return "article/articleReceiveManage";
    }
    
    /**
     * 提交公文审核结果
     * @param map
     * @param taskId
     * @param result
     * @param articleId
     * @param auditmessage
     * @return
     */
    @RequestMapping("/submitAuditResult")
    public String submitAuditResult(Map<String, Object> map, String taskId,
            Integer result, Integer articleId, String auditmessage){
        
        AuditMessage auditMessage = new AuditMessage();
        auditMessage.setAuditdate(new Date());
        auditMessage.setAuditmessage(auditmessage);
        auditMessage.setAuditresult(result);
        auditMessage.setArticleId(articleId);
        
        //先添加审核信息
        if (auditMessageService.addAuditMessage(auditMessage)) {
            
            Map<String, Object> variables = new HashMap<>();
            
            if (result == 1) { //审核通过
                variables.put("auditresult", true);
                
                Article article = new Article();
                article.setArticleid(articleId);
                article.setArticlestate(3); //3表示审核通过且发布
                articleService.modifyArticle(article); //更新数据库字段
            } else {
                variables.put("auditresult", false);
                
                Article article = new Article();
                article.setArticleid(articleId);
                article.setArticlestate(2); //2表示审核驳回
                articleService.modifyArticle(article); //更新数据库字段
            }
            
            //使用流程变量完成待办任务
            taskService.complete(taskId, variables);
            
            map.put("msg", "提交审核结果成功!");
            map.put("result", true);
            
        } else {
            map.put("msg", "提交审核结果失败!");
            map.put("result", false);
        }
        
        return "redirect:/article/toAduit";
    }
    
    /**
     * 下载公文或附件
     * @param session
     * @param filename
     * @param fileId
     * @return
     * @throws Exception
     */
    @RequestMapping("/download")
    public ResponseEntity<byte[]> downloadArticle(HttpSession session, 
            HttpServletRequest request, HttpServletResponse httpServletResponse,
            Integer attachmentid, String fileId) throws Exception {
        
        byte [] body = null;
        
        Attachment attachment = new Attachment();
        attachment.setAttachmentid(attachmentid);
        attachment = attachmentService.findByKeyword(attachment).get(0);
        
        User user = (User) session.getAttribute("user");
        boolean result = articleService.isArticleAvaliable(
                attachment.getArticleId(), user.getUserid());
        
        if (result == true) {
            
            //如果下载的是公文原文而不是附件,则向日志表插入一条日志记录
            if (attachment.getAttachtype() == 0) {
                Log log = new Log();
                log.setBussinessId(attachment.getArticleId());
                log.setIpaddress(IpUtil.getRequestRealIp(request)); //获取ip地址
                log.setOperatorId(user.getUserid());
                log.setOptname("下载公文");
                log.setOpttime(new Date());
                logService.addLog(log);
            }
            
            //通过JackRabbit找到文件,获得输入流
            InputStream in = fileService.getByFileId(fileId);
            body = new byte[in.available()];
            in.read(body);
            
            HttpHeaders headers = new HttpHeaders();
            headers.add("Content-Disposition", "attachment;filename=" 
                    + new String(attachment.getFilename().getBytes(), "ISO-8859-1"));
            HttpStatus statusCode = HttpStatus.OK;
            ResponseEntity<byte[]> response = 
                    new ResponseEntity<byte[]>(body, headers, statusCode);
            return response;
        }
        
        return null;
    }
    
    /**
     * 按id加载公文信息
     * @return
     */
    @RequestMapping("/toAuditPage")
    public String toAuditPage(Map<String, Object> map, 
            HttpSession session, Integer articleId) {
        
        //1.从Session中获得User,取得其UserId
        User user = (User) session.getAttribute("user");
        Integer userId = user.getUserid();
        
        //2. 读取当前用户的待办任务,包括直接分配给当前人或已经签收的任务
        List<Task> doingTask = taskService.createTaskQuery()
                .taskAssignee(user.getUserid().toString()).list();
        
        //2.检查访问权限
        if (articleService.isArticleAvaliable(articleId, userId) == true) {
            
            //3.查询公文信息
            Article article = articleService.getArticleById(articleId, userId); 
            
            //4.根据公文的流程实例id找到当前任务
            Task task = null;
            for (Task task1 : doingTask) {
                if (article.getProcessinstanceId().equals(task1.getProcessInstanceId())) {
                    task = task1;
                }
            }
            
            //3.保存查询结果
            map.put("article", article);
            map.put("task", task);
            return "article/articleAuditDetail";
        } else {
            map.put("msg", "您没有查看公文的权限!");
            map.put("result", false);
            return "forward:/article/toAduit";
        }
    }
    
    /**
     * 按id加载公文审核结果信息
     * @return
     */
    @RequestMapping("/findById")
    public String findById(Map<String, Object> map, HttpSession session,
                HttpServletRequest request, Integer articleId) {
        
        //1.从Session中获得User,取得其UserId
        User user = (User) session.getAttribute("user");
        Integer userId = user.getUserid();
        
        //2.检查访问权限
        if (articleService.isArticleAvaliable(articleId, userId) == true) {
            
            //3.向日志表插入一条日志记录
            Log log = new Log();
            log.setBussinessId(articleId);
            log.setIpaddress(IpUtil.getRequestRealIp(request)); //获取ip地址
            log.setOperatorId(userId);
            log.setOptname("查看公文");
            log.setOpttime(new Date());
            logService.addLog(log);
            
            Article article = articleService.getArticleById(articleId, userId); 
            
            //4.保存查询结果
            map.put("article", article);
            return "article/articleDetail";
        } else {
            map.put("msg", "您没有查看公文的权限!");
            map.put("result", false);
            return "forward:/article/toAduitResult";
        }
    }
    
    /**
     * 进入审核界面
     * @param map
     * @param pageNo
     * @param pageCount
     * @param keyword
     * @return
     */
    @RequestMapping("/toAduit")
    public String toAduit(Map<String, Object> map, HttpSession session,
            @RequestParam(value="keyword", required=false) String keyword) {
        
        // 查询得到结果集
        List<Article> articles;
        
        User user = (User) session.getAttribute("user");
        
        //读取当前用户的待办任务,包括直接分配给当前人或已经签收的任务
        List<Task> doingTask = taskService.createTaskQuery()
                .taskAssignee(user.getUserid().toString()).list();

        if (doingTask != null && doingTask.size() != 0) { //有该用户的待办任务
            
            if (StringUtils.hasText(keyword)) { //用户指定了查询关键字
                articles = articleService.getByProcessInstances(doingTask, keyword, Arrays.asList(0));
            } else { //用户没指定查询关键字
                articles = articleService.getByProcessInstances(doingTask, null, Arrays.asList(0));
            }
        } else { //没有待办任务
            articles = new ArrayList<>();
        }
        
        //保存结果集带到页面显示
        map.put("articles", articles);
        map.put("tasks", doingTask);
        
        //保存模糊查询条件以便回显
        map.put("keyword", keyword);
        
        return "article/articleAuditManage";
    }
    
    /**
     * 进入审核结果
     * @param map
     * @param pageNo
     * @param pageCount
     * @param keyword
     * @return
     */
    @RequestMapping("/toAduitResult")
    public String toAduitResult(Map<String, Object> map, HttpSession session,
            @RequestParam(value="keyword", required=false) String keyword) {
        
        // 查询得到结果集
        List<Article> articles;
        
        User user = (User) session.getAttribute("user");
        
        //读取当前用户的待办任务,包括直接分配给当前人或已经签收的任务
        List<Task> doingTask = taskService.createTaskQuery()
                .taskAssignee(user.getUserid().toString()).list();
        
        if (doingTask != null && doingTask.size() != 0) { //有该用户的待办任务
            
            if (StringUtils.hasText(keyword)) { //用户指定了查询关键字
                articles = articleService.getByProcessInstances(doingTask, keyword, Arrays.asList(1, 2));
            } else { //用户没指定查询关键字
                articles = articleService.getByProcessInstances(doingTask, null, Arrays.asList(1, 2));
            }
        } else { //没有待办任务
            articles = new ArrayList<>();
        }
        
        //为每一篇公文加入对应的Task
        for (Task task : doingTask) {
            for (Article article : articles) {
                if (task.getProcessInstanceId().equals(article.getProcessinstanceId())) {
                    article.setTask(task);
                }
            }
        }
        
        //查询出正在审核中的公文
        Article article = new Article();
        article.setTitle(keyword);
        article.setUserId(user.getUserid());
        List<Article> auditing = articleService.getMyAuditList(article);
        articles.addAll(auditing); //合并两个集合
        
        //保存结果集带到页面显示
        map.put("articles", articles);
        map.put("tasks", doingTask);
        
        //保存模糊查询条件以便回显
        map.put("keyword", keyword);
        
        return "article/articleAuditResultManage";
    }
    
    /**
     * 公文上传(撰稿)
     * @return
     */
    @RequestMapping("/addArticle")
    @Transactional
    public String addArticle(Map<String, Object> map, HttpSession session ,
            String title, 
            Integer[] received, 
            Integer auditor, 
            MultipartFile doc,
            @RequestParam(name= "attachment", required = false) MultipartFile[] attachment) {
        
        try {
            //1.首先检查必填项是否都填写正确
            
            if (validateForm(map, null, title, received, auditor, doc) == false) {
                return "forward:/article/toAdd";
            }
            
            //2.设置公文相关参数并新增公文
            Article article = new Article();
            article.setArticlestate(0); //0表示审核中
            article.setTitle(title);
            
            //撰稿人就是当前用户
            User user = (User)session.getAttribute("user");
            article.setCopywriterId(user.getUserid());
            article.setInstId(user.getInstId());
            
            article.setAuditorId(auditor);
            article.setPublishtime(new Date());
            
            //判断操作结果是否成功
            if (!articleService.addArticle(article)) {
                map.put("msg", "系统出现错误,在添加公文信息时操作失败!");
                map.put("result", false);
                return "forward:/article/toAdd";
            }
            
            //3.启动Activiti工作流流程,拿到流程实例id
            
            //3.1 设置流程变量,指定审核人(为防止用户姓名重复,使用用户id)
            Map<String, Object> variables = new HashMap<String, Object>();
            variables.put("auditorId", auditor);              //指定公文审核的办理人Id
            variables.put("copywriterId", user.getUserid());  //指定撰稿人Id
            
            //3.2 按流程实例id启动流程
            ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(
                    "articleProcess", article.getArticleid().toString() , variables);
            
            //3.3 得到流程实例id
            String procInstanceKey = processInstance.getId();
            
            //3.4 更新公文信息,设置流程id
            article.setProcessinstanceId(procInstanceKey);
            if (!articleService.modifyArticle(article)) {
                map.put("msg", "系统出现错误,在添加公文信息时操作失败!");
                map.put("result", false);
                return "forward:/article/toAdd";
            }
            
            //4 利用公文id继续去添加其他信息
            
            //4.1 添加接收关系
            for (Integer receiverId : received) {
                
                if (!receiveService.addReceive(article.getArticleid(), receiverId)) {
                    map.put("msg", "系统出现错误,在添加公文接收信息时操作失败!");
                    map.put("result", false);
                    return "forward:/article/toAdd";
                }
            }

            //4.2 调用FileService,使用JackRabbit保存公文电子文档
            String fileId = fileService.save(doc.getInputStream());
            
            //4.3 拼装出公文原文的附件信息
            Attachment articleDocument = new Attachment();
            articleDocument.setArticleId(article.getArticleid());
            articleDocument.setAttachtype(0); //0表示正文
            articleDocument.setFilename(doc.getOriginalFilename());
            articleDocument.setMimetype(doc.getContentType());
            articleDocument.setUploadtime(new Date());
            articleDocument.setFilesize(doc.getSize());
            articleDocument.setFileid(fileId); //JackRabbit返回的FileId
            
            //4.4 添加信息到附件表
            if (!attachmentService.addAttachment(articleDocument)) {
                map.put("msg", "系统出现错误,在添加公文附件时操作失败!");
                map.put("result", false);
                return "forward:/article/toAdd";
            }
            
            //5.如果用户上传了附件,就要把附件也保存下来
            
            for (MultipartFile attachFile : attachment) {
                
                //5.1 调用FileService,使用JackRabbit保存公文附件
                String attfileId = fileService.save(attachFile.getInputStream());
                
                //5.2 拼装附件信息
                Attachment attch = new Attachment();
                attch.setArticleId(article.getArticleid());
                attch.setAttachtype(1); //1表示附件
                attch.setFileid(attfileId);
                attch.setFilename(attachFile.getOriginalFilename());
                attch.setFilesize(attachFile.getSize());
                attch.setMimetype(attachFile.getContentType());
                attch.setUploadtime(new Date());
                
                //5.3 添加信息到附件表
                if (!attachmentService.addAttachment(attch)) {
                    map.put("msg", "系统出现错误,在添加公文附件时操作失败!");
                    map.put("result", false);
                    return "forward:/article/toAdd";
                }
                
            }

            //6.如果以上操作都没有问题,那就是成功了
            map.put("msg", "公文[" + article.getTitle() + "]上传成功,请耐心等待审核!");
            map.put("result", true);
            
            //返回等待审核结果界面
            return "forward:/article/toAduitResult";
        } catch (Exception e) {
            System.out.println("公文撰稿出错!");
            e.printStackTrace();
            
            map.put("msg", "系统出现严重错误,公文撰稿操作失败!");
            map.put("result", false);
            return "forward:/article/toAdd";
        }
    }

    /**
     * 检查公文撰稿表单是否填写正确
     * @param map
     * @param title
     * @param received
     * @param auditor
     * @param doc
     * @return
     */
    private boolean validateForm(Map<String, Object> map, Integer articleid, 
            String title, Integer[] received, Integer auditor, MultipartFile doc) {
        
        //1.1检查公文标题是否符合规定格式
        if (StringUtils.hasText(title) == false 
                || Pattern.matches("^\\S{2,150}$", title) == false) {
            map.put("msg", "您填写的公文标题不合法,上传失败!公文标题不能为空,并且长度为2~150。");
            map.put("result", false);
            return false;
        }
        
        //1.2 检查接收人id是否填写
        if (received == null || received.length == 0) {
            map.put("msg", "您还没有选择接收人,上传失败!");
            map.put("result", false);
            return false;
        }
        
        //1.3 检查审核人是否填写
        if (articleid == null && auditor == null) {
            map.put("msg", "您还没有选择审核人,上传失败!");
            map.put("result", false);
            return false;
        }
        
        //1.4 检查公文电子文档是否上传
        if (articleid == null && doc == null) {
            map.put("msg", "您还没有上传公文电子文档,上传失败!");
            map.put("result", false);
            return false;
        }
        
        //1.5 检查公文名称是否重复,如果重复则不允许其通过
        if (articleService.validateTitle(title, articleid) == false) {
            map.put("msg", "您填写的公文标题与已有标题重复,上传失败!");
            map.put("result", false);
            return false;
        }
        
        return true;
    }
    
    /**
     * 进入公文撰稿界面
     * @return
     * @throws Exception 
     */
    @RequestMapping("/toAdd")
    public String toAdd(HttpSession session, Map<String, Object> map) throws Exception {
        
        //加载出该用户所在机构所有审稿人姓名
        
        //1 从Session中取出User
        User user = (User) session.getAttribute("user");
        
        //2 通过用户得到其所在机构的id
        Integer instid = user.getInstId();
        
        //3 得到该机构所有未被禁用的审核人员的信息
//        List<User> auditors = userService.findValidAuditor(instid);
        List<User> auditors = userService.findValidAuditorRoleId(instid, user.getRoleId());

        //4 保存为备选项
        map.put("auditors", auditors);
        
        return "article/articleupload";
    }
    
    /**
     * 通过Ajax方式获得联系人树
     * @return
     * @throws Exception
     */
    @ResponseBody
    @RequestMapping("/getTree")
    public List<TreeDto> getTree() throws Exception {
        
        List<TreeDto> dtos = new ArrayList<>();
        dtos.add(articleService.getTreeDTOJSON(null, null));
        return dtos;
    }
    
}

 

服务层:ArticleService.java

package cn.edu.nuc.article.service;

import java.util.List;

import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import cn.edu.nuc.article.dao.ArticleMapper;
import cn.edu.nuc.article.dto.State;
import cn.edu.nuc.article.dto.TreeDto;
import cn.edu.nuc.article.entity.Article;
import cn.edu.nuc.article.entity.Institution;
import cn.edu.nuc.article.entity.User;

/**
 * 公文Service
 * @author 仰望星空
 *
 */
@Service
public class ArticleService {

    /**
     * 公文Mapper
     */
    @Autowired
    private ArticleMapper articleMapper;
    
    /**
     * 用户Service
     */
    @Autowired
    private UserService userService;
    
    /**
     * 机构Service
     */
    @Autowired
    private InstitutionService institutionService;
    
    /**
     * 得到被驳回公文的数量
     * @param userId 用户id
     * @return
     */
    public Long getWaitCount(Integer userId){
        return articleMapper.selectMyWaitingCount(userId);
    }
    
    /**
     * 得到被驳回公文的数量
     * @param userId 用户id
     * @return
     */
    public Long getFailCount(Integer userId){
        return articleMapper.selectMyFailCount(userId);
    }
    
    /**
     * 得到待处理公文数量
     * @param userId 用户id
     * @return
     */
    public Long getDealCount(Integer userId) {
        
        return articleMapper.selectMyDealCount(userId);
    }
    
    /**
     * 得到待接收公文数量
     * @param userId 用户ID
     * @return
     */
    public Long getReceivedCount(Integer userId) {
        return articleMapper.selectMyCountReceiver(userId);
    }
    
    /**
     * 检查公文是否可以被访问
     * @param articleId
     * @param userId
     * @return
     */
    public boolean isArticleAvaliable(Integer articleId, Integer userId) {
        
        return articleMapper.validateAccess(userId, articleId) > 0;
    }
    
    /**
     * 通过流程实例id加载功能信息
     * @param ids
     * @return
     */
    public List<Article> getByProcessInstances(List<Task> tasks, String title, List<Integer> articlestates) {
        
        return articleMapper.selectByProcessInstances(tasks, title, articlestates);
    }
    
    /**
     * 按id加载公文记录
     * @param articleId 公文Id
     * @return
     */
    public Article getArticleById(Integer articleId, Integer userId) {
        
        return articleMapper.selectOne(articleId, userId);
    }
    
    /**
     * 查询出与我相关的公文
     * @param article
     * @return
     */
    public List<Article> getMyArticles(Article article) {
        
        return articleMapper.selectMyReceiveList(article);
    }
    
    /**
     * 找出与我相关的公文
     * @param article
     * @return
     */
    public List<Article> getMyAuditList(Article article) {
        
        return articleMapper.selectMyAuditList(article);
    }
    
    /**
     * 找出与我相关的公文
     * @param article
     * @return
     */
    public List<Article> getMyArticleList(Article article) {
        
        return articleMapper.selectMyList(article);
    }
    
    /**
     * 测试公文标题是否重复
     * @param title
     * @return true 不重复。 false 重复
     */
    public boolean validateTitle(String title, Integer articleid) {
        
        return articleMapper.validateTitle(title, articleid) == 0;
    }
    
    /**
     * 更新公文信息
     * @param article
     * @return
     */
    public boolean modifyArticle(Article article) {
        
        return articleMapper.updateByPrimaryKeySelective(article) > 0;
    }
    
    /**
     * 添加公文
     * @return
     */
    public boolean addArticle(Article article) {
        
        return articleMapper.insertSelective(article) > 0;
    }
    
    /**
     * 获得树的DTO对象的JSON字符串
     * @return
     * @throws Exception 
     */
    public TreeDto getTreeDTOJSON(Integer articleId, Integer userId) throws Exception {
        
        //1.加载出所有的未被禁用的机构
        
        //1.1 设置查询条件,要求机构的状态必须是正常,即不可以是禁用或者被合并
        Institution institution1 = new Institution();
        institution1.setInststate(1);  //1代表正常
        
        //1.2 使用查询条件拿到结果集
        List<Institution> institutions = institutionService.findByKeyword(institution1);
        
        //2.加载出未被禁用的用户
        List<User> users = userService.findValidUser();
        
        //3.如果有公文id,还要查询出公文信息(修改公文时用)
        Article article = null;
        if (articleId != null) {
            article = articleMapper.selectOne(articleId, userId);
        }
        
        return getTree(institutions, users, article);
    }

    /**
     * 根据机构和用户信息装出联系人树对象
     * @param institutions 机构信息
     * @param users 用户信息
     * @return 联系人树
     */
    private TreeDto getTree(List<Institution> institutions, List<User> users,
            Article article) {

        //标志位
        boolean isFirstLevelSelected = false;
        
        //1 先构造出树的根
        TreeDto root = new TreeDto();
        root.setText("所有联系人");
        
        //2 遍历每一个机构
        for (Institution institution : institutions) {
            
            //3.2 为当前机构构建出一个一级子节点
            TreeDto firstLevel = new TreeDto();
            firstLevel.setText(institution.getInstname());  //节点名称就是机构名称
            
            boolean isSecondLevelSelected = false;
            
            //3.3 遍历每一个用户
            for (User user : users) {
                
                //3.4 如果这个用户属于当前机构
                if (user.getInstId() == institution.getInstid()) {
                    
                    //3.5 为当前用户创建子节点
                    TreeDto secondLevel = new TreeDto();
                    secondLevel.setText(user.getUsertruename()); //节点名称是用户真实姓名
                    secondLevel.setId(user.getUserid()); //用户节点的id就是用户id,只有用户节点才有id
                    
                    //判断是否需要设置选中
                    if (article != null) {
                        List<User> receivers = article.getReceivers();
                        for (User receiver : receivers) {
                            if (user.getUserid() == receiver.getUserid()) {
                                State state = new State();
                                state.setChecked(true);
                                secondLevel.setState(state);
                                isSecondLevelSelected = true;
                            }
                        }
                    }
                    
                    //3.6把用户节点加到机构节点下面
                    firstLevel.addNode(secondLevel);

                }//if
            }//for user
            
            //3.7判断是否勾选
            if (isSecondLevelSelected == true) {
                isFirstLevelSelected = true;
                State state = new State();
                state.setChecked(true);
                firstLevel.setState(state);
            }

            //3.8 把机构节点加入到根节点下面
            root.addNode(firstLevel);
        }
        
        if (isFirstLevelSelected == true) {
             State state = new State();
             state.setChecked(true);
             root.setState(state);
        }
        
        return root;
    }
}

 

数据访问对象:ArticleMapper.java

package cn.edu.nuc.article.dao;

import java.util.List;

import org.activiti.engine.task.Task;
import org.apache.ibatis.annotations.Param;

import cn.edu.nuc.article.entity.Article;

/**
 * 公文Mapper
 * @author 仰望星空
 *
 */
public interface ArticleMapper {

    /**
     * 插入一条公文信息(公文撰稿时调用)
     * @param record
     * @return
     */
    int insertSelective(Article record);

    /**
     * 修改一条公文信息
     * @param record
     * @return
     */
    int updateByPrimaryKeySelective(Article record);

    /**
     * 模糊查询全部
     * @param article
     * @return
     */
    List<Article> selectListAll(Article article);
    
    /**
     * 查与我有关的信息
     * @param article
     * @return
     */
    List<Article> selectMyReceiveList(Article article);
    
    /**
     * 查询审核结果中正在审核的公文
     * @param article
     * @return
     */
    List<Article> selectMyAuditList(Article article);
    
    /**
     * 查与我有关的信息
     * @param article
     * @return
     */
    List<Article> selectMyList(Article article);
    
    /**
     * 按照流程实例id加载公文信息
     * @param ids
     * @return
     */
    List<Article> selectByProcessInstances(
            @Param("tasks") List<Task> tasks, 
            @Param("title") String title, 
            @Param("articlestates") List<Integer> articlestates);
    
    /**
     * 按id查询公文详细信息
     * @param articleid
     * @return
     */
    Article selectOne(@Param("articleid") Integer articleid,  
            @Param("userId") Integer userId);
    
    /**
     * 检查公文是否可以被下载和查看
     * @param userId
     * @param articleid
     * @return
     */
    Long validateAccess(@Param("userId") Integer userId, 
            @Param("articleid") Integer articleid);
    
    /**
     * 查询等待审核通过公文的数量
     * @param userId 用户id
     * @return
     */
    Long selectMyWaitingCount(Integer userId);
    
    /**
     * 查询被驳回的公文数量
     * @param userId 用户id
     * @return
     */
    Long selectMyFailCount(Integer userId);
    
    /**
     * 查询需要我审核的公文数量
     * @param userId 用户id
     * @return
     */
    Long selectMyDealCount(Integer userId);
    
    /**
     * 查询待收取公文数量
     * @param userId 用户id
     * @return
     */
    Long selectMyCountReceiver(Integer userId);
    
    /**
     * 撰稿人删除公文
     * @param articleid
     * @return
     */
    Integer deleteById(Integer articleid);
    
    /**
     * 检查公文标题是否重复
     * @param title
     * @return
     */
    Long validateTitle(@Param("title") String title, 
            @Param("articleid") Integer articleid);
}

 

实体类:Article.java

package cn.edu.nuc.article.entity;

import java.io.Serializable;
import java.util.Date;
import java.util.List;

import org.activiti.engine.task.Task;

/**
 * 公文
 * @author 仰望星空
 *
 */
public class Article implements Serializable {
    
    /**
     * 序列化id
     */
    private static final long serialVersionUID = 1L;

    /**
     * 公文id
     */
    private Integer articleid;

    /**
     * 公文标题
     */
    private String title;

    /**
     * 发布时间
     */
    private Date publishtime;

    /**
     * 撰稿人id
     */
    private Integer copywriterId;
    
    /**
     * 存放级联查询出来的撰稿人信息(数据库没字段对应)
     */
    private User copywriter;

    /**
     * 审稿人id
     */
    private Integer auditorId;
    
    /**
     * 存放级联查询出来的审稿人信息(数据库没字段对应)
     */
    private User auditor;

    /**
     * 发布机构id
     */
    private Integer instId;
    
    /**
     * 存放级联查询出来的发布机构信息(数据库没字段对应)
     */
    private Institution institution;
    
    /**
     * 公文状态:
     * 0 审核中
     * 1 审核通过
     * 2 审核驳回
     * 3 公文发布
     * 4 公文删除
     */
    private Integer articlestate;
    
    /**
     * 流程实例Id
     */
    private String processinstanceId;

    /**
     * 点击量
     */
    private Long clickcount;
    
    /**
     * 下载量
     */
    private Long downloadcount;
    
    /**
     * 附件
     */
    private List<Attachment> attachments;
    
    /**
     * 校验信息
     */
    private List<AuditMessage> auditMessages;
    
    /**
     * 接收人
     */
    private List<User> receivers;
    
    /**
     * 加载和自己有关的列表时使用
     */
    private Integer userId;
    
    /**
     * 任务
     */
    private Task task;

    public Integer getArticleid() {
        return articleid;
    }

    public void setArticleid(Integer articleid) {
        this.articleid = articleid;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public Date getPublishtime() {
        return publishtime;
    }

    public void setPublishtime(Date publishtime) {
        this.publishtime = publishtime;
    }

    public Integer getCopywriterId() {
        return copywriterId;
    }

    public void setCopywriterId(Integer copywriterId) {
        this.copywriterId = copywriterId;
    }

    public User getCopywriter() {
        return copywriter;
    }

    public void setCopywriter(User copywriter) {
        this.copywriter = copywriter;
    }

    public Integer getAuditorId() {
        return auditorId;
    }

    public void setAuditorId(Integer auditorId) {
        this.auditorId = auditorId;
    }

    public User getAuditor() {
        return auditor;
    }

    public void setAuditor(User auditor) {
        this.auditor = auditor;
    }

    public Integer getInstId() {
        return instId;
    }

    public void setInstId(Integer instId) {
        this.instId = instId;
    }

    public Institution getInstitution() {
        return institution;
    }

    public void setInstitution(Institution institution) {
        this.institution = institution;
    }

    public Integer getArticlestate() {
        return articlestate;
    }

    public void setArticlestate(Integer articlestate) {
        this.articlestate = articlestate;
    }

    public String getProcessinstanceId() {
        return processinstanceId;
    }

    public void setProcessinstanceId(String processinstanceId) {
        this.processinstanceId = processinstanceId;
    }

    public Long getClickcount() {
        return clickcount;
    }

    public void setClickcount(Long clickcount) {
        this.clickcount = clickcount;
    }

    public Long getDownloadcount() {
        return downloadcount;
    }

    public void setDownloadcount(Long downloadcount) {
        this.downloadcount = downloadcount;
    }

    public List<Attachment> getAttachments() {
        return attachments;
    }

    public void setAttachments(List<Attachment> attachments) {
        this.attachments = attachments;
    }

    public List<AuditMessage> getAuditMessages() {
        return auditMessages;
    }

    public void setAuditMessages(List<AuditMessage> auditMessages) {
        this.auditMessages = auditMessages;
    }

    public List<User> getReceivers() {
        return receivers;
    }

    public void setReceivers(List<User> receivers) {
        this.receivers = receivers;
    }

    public Integer getUserId() {
        return userId;
    }

    public void setUserId(Integer userId) {
        this.userId = userId;
    }

    public Task getTask() {
        return task;
    }

    public void setTask(Task task) {
        this.task = task;
    }

    @Override
    public String toString() {
        return "\n----------------\n"
                + "Article [articleid=" + articleid 
                + ", \ntitle=" + title 
                + ", \npublishtime=" + publishtime
                + ", \ncopywriterId=" + copywriterId 
                + ", \ncopywriter=" + copywriter 
                + ", \nauditorId=" + auditorId
                + ", \nauditor=" + auditor 
                + ", \ninstId=" + instId 
                + ", \ninstitution=" + institution 
                + ", \narticlestate=" + articlestate 
                + ", \nprocessinstanceId=" + processinstanceId 
                + ", \nclickcount=" + clickcount
                + ", \ndownloadcount=" + downloadcount 
                + ", \nattachments=" + attachments 
                + ", \nauditMessages=" + auditMessages 
                + ", \nreceivers=" + receivers 
                + ", \nuserId=" + userId + "]\n--------------\n";
    }

    /**
     * 以公文id为唯一标示
     */
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((articleid == null) ? 0 : articleid.hashCode());
        return result;
    }

    /**
     * 以公文id为唯一标示
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Article other = (Article) obj;
        if (articleid == null) {
            if (other.articleid != null)
                return false;
        } else if (!articleid.equals(other.articleid))
            return false;
        return true;
    }   
}

 

国密算法:

Part2 各个成员遇到的问题

  •  继续开发公文传输功能(20211302):编辑和查看功能复杂性: 实现公文的查看和编辑功能可能牵涉到富文本编辑、版本控制等复杂的需求。选择适当的富文本编辑库,确保编辑器的易用性和功能丰富性。使用版本控制系统,追踪和管理公文的修改历史。进行用户测试,确保用户能够轻松使用编辑和查看功能。
  •  完善权限表,实现细粒度的权限控制(20211304):权限设计复杂性: 实现细粒度的权限控制可能需要考虑到各种操作和资源的权限设置。利用 RBAC 或 ABAC 模型,将权限分配与角色关联,以简化权限管理。进行系统内的模拟测试,验证各种场景下权限的正常工作。使用权限管理工具,简化权限设置和维护。
  •  处理用户管理功能的反馈(20211308):稳定性问题: 用户管理功能的反馈可能包括系统崩溃、性能问题等方面的反馈。进行详细的日志记录,以便在出现问题时能够快速定位和解决。使用监控工具实时监测系统的性能。进行持续集成和自动化测试,确保每次代码变更都不会引入新的稳定性问题。
  • 继续开发日志记录功能,记录更多的操作信息(20211317):日志记录性能和存储问题: 记录大量的操作信息可能导致性能问题和存储成本增加。选择适当的日志记录库,确保能够满足性能需求。进行日志的归档和定期清理,以控制存储成本。根据实际需求,采用异步方式记录日志,减轻对主业务逻辑的影响。
  • 完成国密算法的集成和性能优化(20211318):性能优化困难: 集成国密算法后,可能需要优化算法以提高性能。进行性能分析,找到性能瓶颈。考虑使用硬件加速、并行计算等方式优化算法。使用缓存技术,避免重复计算。进行性能测试,确保优化效果符合预期。

 Part3 明日各个成员的任务安排

  • 20211302:继续开发公文传输功能,实现公文的审批和流转。
  • 20211304:测试权限控制功能,确保权限生效。
  • 20211308:进行用户管理功能的系统测试,修复可能存在的漏洞。
  • 20211317:继续完善日志记录功能,确保记录的完整性。
  • 20211318:进行国密算法的性能测试和安全性评估。

Part4 各个成员今日对项目的贡献量

 

Part5 燃尽图与站立式会议照片

 

posted @ 2023-11-24 11:17  DKY——仰望星空  阅读(7)  评论(0编辑  收藏  举报
$