仰望星空——冲刺日志Day4
Part1 各个成员今日完成的任务
- 20211302:继续开发公文传输功能,实现文件的存储和管理。
- 20211304:创建权限表,为访问控制功能做准备。
- 20211308:测试用户管理功能,确保权限分配正常工作。
- 20211317:完成访问控制功能的开发,实现基本的访问限制。
- 20211318:测试国密算法的性能和安全性。
公文接收功能实现
package cn.edu.nuc.article.dao;
import org.apache.ibatis.annotations.Param;
/**
* 公文接收信息Mapper
* @author 仰望星空
*
*/
public interface ReceiveMapper {
/**
* 删除某一条公文下的所有接收信息
* @param articleid
* @return
*/
int deleteByArticleId(Integer articleid);
/**
* 公文添加一个接收人
* @param record
* @return
*/
int insertSelective(@Param("articleId") Integer articleId,
@Param("receiverId") Integer receiverId);
}
系统日志设计
package cn.edu.nuc.article.entity;
import java.io.Serializable;
import java.util.Date;
/**
* 系统日志
* @author 仰望星空
*
*/
public class Log implements Serializable {
/**
* 序列化id
*/
private static final long serialVersionUID = 1L;
/**
* 日志id
*/
private Integer logid;
/**
* 操作名称
*/
private String optname;
/**
* 业务id(非物理外键,但是却起到了物理外键的作用)
*/
private Integer bussinessId;
/**
* 操作人id(物理外键)
*/
private Integer operatorId;
/**
* 操作人(级联出来的对象,不是真实的数据库列)
*/
private User operator;
/**
* 操作时间(就是取添加日志时候服务器当前系统的时间)
*/
private Date opttime;
/**
* 操作人登陆的ip地址
*/
private String ipaddress;
public Integer getLogid() {
return logid;
}
public void setLogid(Integer logid) {
this.logid = logid;
}
public String getOptname() {
return optname;
}
public void setOptname(String optname) {
this.optname = optname == null ? null : optname.trim();
}
public Integer getBussinessId() {
return bussinessId;
}
public void setBussinessId(Integer bussinessId) {
this.bussinessId = bussinessId;
}
public Integer getOperatorId() {
return operatorId;
}
public void setOperatorId(Integer operatorId) {
this.operatorId = operatorId;
}
public Date getOpttime() {
return opttime;
}
public void setOpttime(Date opttime) {
this.opttime = opttime;
}
public String getIpaddress() {
return ipaddress;
}
public void setIpaddress(String ipaddress) {
this.ipaddress = ipaddress == null ? null : ipaddress.trim();
}
public User getOperator() {
return operator;
}
public void setOperator(User operator) {
this.operator = operator;
}
@Override
public String toString() {
return "Log [logid=" + logid + ", optname=" + optname + ", bussinessId=" + bussinessId + ", operatorId="
+ operatorId + ", operator=" + operator + ", opttime=" + opttime + ", ipaddress=" + ipaddress + "]";
}
//以logid作为唯一标示
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((logid == null) ? 0 : logid.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Log other = (Log) obj;
if (logid == null) {
if (other.logid != null)
return false;
} else if (!logid.equals(other.logid))
return false;
return true;
}
}
验证码生成工具
package cn.edu.nuc.article.util;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* 生成验证码工具
* @author 仰望星空
*
*/
public final class CodeUtil {
/**
* 验证码字体
*/
private static Font[] codeFont = {
new Font("Times New Roman", Font.PLAIN,30),
new Font("Times New Roman", Font.PLAIN,30),
new Font("Times New Roman", Font.PLAIN,30),
new Font("Times New Roman", Font.PLAIN,30)
};
/**
* 验证码字符颜色
*/
private static Color[] color = {
Color.BLACK, Color.RED, Color.DARK_GRAY, Color.BLUE
};
/**
* 生成验证码的字符(A-Z,a-z,0-9),验证码形成时将会从这里选取字符
*/
private static final String IMAGE_CHAR = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijkmnpqrstuvwxyz23456789";
/**
* 生成验证码图片的宽度
*/
private static final Integer IMAGE_WIDTH = 160;
/**
* 生成验证码图片的高度
*/
private static final Integer IMAGE_HEIGHT = 40;
/**
* 功能函数:绘制验证码的一个字符
* @param graphics 绘图对象(画笔)
* @param i 验证码字符序号
*/
private static String drawCode(Graphics graphics, int i){
Random random = new Random();
//产生随机切割序号 0-61.9999
Integer j = random.nextInt((IMAGE_CHAR.length()));
//切割随机数
String number = IMAGE_CHAR.substring(j, j+1);
//设置验证码字符的字体和颜色
graphics.setFont(codeFont[i]);
graphics.setColor(color[i]);
//绘制验证码到图片X、Y(每个字体x每步进13的倍数,y不变,大小6*6)
//number是要绘制字符的值,
//6 + i * 13 是要绘制的x轴坐标,x轴递增13实现字符之间间距为13
//16是指字符绘制的y轴坐标
graphics.drawString(number, 22 + i * 26, 28);
return number;
}
/**
* 产生随机背景色
* @param fc 颜色基调
* @param bc 颜色边界
* @return 随机产生的背景色
*/
private static Color getRandColor(int fc,int bc){
//随机对象
Random random = new Random();
//随机初始数值不得大于255
if(fc > 255)
fc = 255;
//随机初始数值不得大于255
if(bc > 255)
bc = 255;
//产生随机红蓝绿色调
int r = fc + random.nextInt(bc - fc);
int g = fc + random.nextInt(bc - fc);
int b = fc + random.nextInt(bc - fc);
return new Color(r,g,b);
}
/**
* 功能函数:绘制干扰线
* @param graphics 绘图对象(画笔)
* @param lineNumber 干扰线条数
*/
private static void drawNoise(Graphics graphics, int lineNumber){
//干扰线颜色
graphics.setColor(getRandColor(160, 200));
for (int i = 0; i < lineNumber; i++) {
//线的起始X轴(只在80,20的范围内随机,由于从0开始,所以要加1)
int pointX1 = 1 + (int) (Math.random() * 160);
//Math类的random()方法生成0.0-1.0之间的随机数
//线的起始Y轴(只在80,20的范围内随机,由于从0开始,所以要加1)
int pointY1 = 1 + (int) (Math.random() * 40);
//线的终止X轴(只在80,20的范围内随机,由于从0开始,所以要加1)
int pointX2 = 1 + (int) (Math.random() * 160);
//线的终止Y轴(只在80,20的范围内随机,由于从0开始,所以要加1)
int pointY2 = 1 + (int) (Math.random() * 40);
graphics.drawLine(pointX1, pointY1, pointX2, pointY2);
}
}
/**
* 覆写doGet方法,完成验证码的生成
*/
public static void drawCode(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
response.setContentType("image/gif");
//不设置缓存,页面不使用缓存
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
//创建一个图像,验证码显示图片大小
BufferedImage image = new BufferedImage(IMAGE_WIDTH, IMAGE_HEIGHT,
BufferedImage.TYPE_INT_RGB);
//BufferedImage.TYPE_INT_RGB表示图片中的每一个像素都可以由红绿蓝三种色调
//获取图片绘制对象(画笔)
Graphics g = image.getGraphics();
//绘制图片背景颜色
g.setColor(getRandColor(200, 250));
//绘制背景图片
g.fillRect(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);
//前两个参数是指图形区域开始(左上角)的横纵坐标
//后两个参数是指图形区域的宽度和高度
String codeNumbers = "";
//循环产生4位随机数
for (int i = 0; i < 4; i++) {
codeNumbers = codeNumbers + drawCode(g, i);
}
//添加干扰线
drawNoise(g, 12);
//将验证码内容保存进session中,用于验证用户输入是否正确时使用
HttpSession session = request.getSession(true);
session.removeAttribute("code");
session.setAttribute("code", codeNumbers);
//利用ImagieIO类的write方法对图像进行编码
ServletOutputStream sos = response.getOutputStream();
ImageIO.write(image, "GIF", sos);
sos.close();
}
}
Part2 各个成员遇到的问题
- 继续开发公文传输功能(20211302):文件存储和管理策略: 面临选择合适的文件存储方式和管理策略,包括文件系统存储、云存储等。进行需求分析,考虑文件大小、访问频率、安全性等因素选择存储方式。使用文件命名规范和目录结构来管理文件。可以考虑使用分布式文件系统或对象存储解决大规模文件管理的问题。
- 创建权限表(20211304):权限设计复杂性: 在创建权限表时,可能涉及到权限的层级、继承、角色等复杂的设计。使用 RBAC 模型,合理划分角色和权限,避免权限表膨胀。进行权限需求分析,确保权限的继承关系和层级结构清晰。定期审查和更新权限表,保持其简洁和可维护性。
- 测试用户管理功能(20211308):权限分配和撤销问题: 测试用户管理功能时,可能需要验证权限的正确分配和撤销。编写全面的测试用例,验证各种情况下的权限分配和撤销。进行系统内的模拟测试,确保在各种场景下权限的正常工作。使用自动化测试工具,加速测试过程。
- 完成访问控制功能的开发(20211317):访问控制规则复杂性: 开发访问控制功能时,可能面临规则的定义、解析和执行的复杂性。使用规则引擎,简化访问控制规则的定义和执行。设计清晰的规则语法,使规则易于理解和维护。进行单元测试和集成测试,确保访问控制功能的准确性。
- 测试国密算法的性能和安全性(20211318):算法配置和使用问题: 在测试国密算法时,可能需要正确配置算法参数,确保其在实际环境中的性能和安全性。确保正确选择和配置国密算法及其参数。进行性能测试,考察在不同负载下算法的表现。进行安全性评估,验证算法的抗攻击性和安全性。可以利用专业的加密算法库,确保配置正确性。
Part3 明日各个成员的任务安排
- 20211302:继续开发公文传输功能,实现文件的版本管理。
- 20211304:继续完善权限表,确保权限设置灵活性。
- 20211308:处理用户管理功能的反馈,修复可能存在的问题。
- 20211317:开始开发日志记录功能,记录用户操作和系统事件。
- 20211318:进行国密算法的集成测试,确保与其他功能的兼容性。
Part4 各个成员今日对项目的贡献量
Part5 燃尽图与站立式会议照片