java实现自动编号系统(类似于word中自动编号)

功能需求:

1,根据章节和当前标题数量,获得下一个编号,满足不同等级编号需求.如同word中的自动编号功能一样

2,可以实现在freemarker中直接调用生成方法,得到正确的编号

目标:即在freemarker代码中通过一个方法调用即可得到当前章节的编号

1
1.1
1.2
2
2.1
2.1.1
2.1.2
2.2
2.2.1
3
3.1
3.1.1
3.1.1.1
3.2


思路:

1,编号整体上是树形结构,因此要用树来管理整个列表

2,有一个方法可以根据最大值,获取下一个(比如:最大值3,下一个4,最大值四,下一个五),这种增量方式是可以扩展和重新定义的.

3,章节间的分隔符是可以指定的,在定义过程中应该指定.

不多说,上代码:

public abstract class Number {
	public abstract String produceNext(String crrnt);

	public String rootNumber() {
		return "0";
	}

	public String firstNumber() {
		return "1";
	}
}
编号抽象类,定义编号的元素类(如1,2,3或一,二,三)

实现类:

public class SerialNumber extends Number {

	@Override
	public String produceNext(String crrnt) {

		String next = "0";
		if (crrnt != null) {
			try {
				int crrntNum = Integer.parseInt(crrnt);
				next = String.valueOf(crrntNum + 1);
			} catch (Exception e) {
				System.err.println("非数字类型的字符串!");
			}
		}
		return next;
	}
}

节点类:

public class Node implements Comparable<Node> {
	private String id;
	private String number;
	private String text;
	private String parentId;
	private int level;

	public Node(String id, String number, String parentId, int level) {
		this.id = id;
		this.number = number;
		this.parentId = parentId;
		this.level = level;
	}

	public Node() {

	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getNumber() {
		return number;
	}

	public void setNumber(String number) {
		this.number = number;
	}

	public String getText() {
		return text;
	}

	public void setText(String text) {
		this.text = text;
	}

	public String getParentId() {
		return parentId;
	}

	public void setParentId(String parentId) {
		this.parentId = parentId;
	}

	public int getLevel() {
		return level;
	}

	public void setLevel(int level) {
		this.level = level;
	}

	@Override
	public int compareTo(Node o) {
		if (this.level != o.level) {
			return o.level - this.level;
		} else {
			if(this.number==null){
				return -1;
			}
			return this.number.compareTo(o.number);
		}
	}

	@Override
	public String toString() {

		return "id=" + this.id + " pId=" + this.parentId + " number=" + this.number + " text=" + this.text + "\r\n";
	}
}

具体操作过程:

public class NumberTree {
	private String id;
	private List<Node> nodeList;
	private String separator;
	private int idSeq;

	private Number number;

	public NumberTree() {
		init();
	}

	public NumberTree(String separator, Number number) {
		init();
		this.separator = separator;
		this.number = number;

	}

	public void init() {
		idSeq = 0;
		this.separator = ".";
		if (this.nodeList == null) {
			nodeList = new ArrayList<Node>();
		}
	}

	public String getId() {
		return id;
	}

	public void setSerialId(String id) {
		this.id = id;
	}

	public String getSeparator() {
		return separator;
	}

	public void setSeparator(String separator) {
		this.separator = separator;
	}

	public List<Node> getNodeList() {
		return nodeList;
	}

	public void setNodeList(List<Node> nodeList) {
		this.nodeList = nodeList;
	}
	/**
	 * 
	  * <p>功能描述:根据父节点获取所有子节点。</p>	
	  * @param pNode
	  * @return
	  * @since JDK1.6。
	  * <p>创建日期:2015-4-23 下午8:20:47。</p>
	  * <p>更新日期:[日期YYYY-MM-DD][变更描述]。</p>
	 */
	public List<Node> getChildNodes(Node pNode) {
		String pId = pNode.getId();
		return getChildNodes(pId);
	}

	/**
	 * 
	  * <p>功能描述:根据父节点获取所有子节点。</p>	
	  * @param pId
	  * @return
	  * @since JDK1.6。
	  * <p>创建日期:2015-4-23 下午8:21:02。</p>
	  * <p>更新日期:[日期YYYY-MM-DD][变更描述]。</p>
	 */
	public List<Node> getChildNodes(String pId) {
		List<Node> childNodes = new ArrayList<Node>();
		for (Node n : nodeList) {
			if (pId.equals(n.getParentId())) {
				childNodes.add(n);
			}
		}

		return childNodes;
	}

	/**
	 * 
	  * <p>功能描述:本级最大节点的下一个。</p>	
	  * @param level
	  * @return
	  * @since JDK1.6。
	  * <p>创建日期:2015-4-23 下午7:44:15。</p>
	  * <p>更新日期:[日期YYYY-MM-DD][变更描述]。</p>
	 */
	public Node generateNextNodeForThisLevel(Node node) {
		Node nextNode = null;
		Node maxNode = getMaxNodeForThisLevel(node);
		String nextNumber = number.firstNumber();
		int level = node.getLevel();
		if (maxNode != null && !"0".equals(maxNode.getId())) {//本级存在子节点,且非根节点
			nextNumber = number.produceNext(maxNode.getNumber());
			level = maxNode.getLevel();
		}
		nextNode = new Node(String.valueOf(++idSeq), nextNumber, node.getId(), level);

		generateNodeText(nextNode, nextNumber);
		return nextNode;
	}

	/**
	 * 
	  * <p>功能描述:获取本级值最大的节点。</p>	
	  * @param level
	  * @return
	  * @since JDK1.6。
	  * <p>创建日期:2015-4-23 下午7:43:26。</p>
	  * <p>更新日期:[日期YYYY-MM-DD][变更描述]。</p>
	 */
	public Node getMaxNodeForThisLevel(Node pNode) {
		List<Node> childList = getChildNodes(pNode);
		Node root = getRoot(nodeList);
		if (childList.size() <= 0) {
			return null;
		}
		int level = pNode.getLevel();
		Node maxNode = root;
		for (Node node : childList) {
			if (maxNode.getNumber().compareTo(node.getNumber()) < 0) {
				maxNode = node;
			}
		}
		return maxNode;
	}

	/**
	  * 
	  * <p>功能描述:根据内容获取节点。</p>	
	  * @param text
	  * @return
	  * @since JDK1.6。
	  * <p>创建日期:2015-4-23 下午8:34:44。</p>
	  * <p>更新日期:[日期YYYY-MM-DD][变更描述]。</p>
	  */
	public Node getNodeByText(String text) {
		Node node = null;
		for (Node n : nodeList) {
			if (text.equals(n.getText())) {
				node = n;
			}
		}

		return node;
	}

	/**
	 * 
	  * <p>功能描述:生成下一个子节点。</p>	
	  * @param node 父节点或兄弟节点 生成根节点时设为null
	  * @return
	  * @since JDK1.6。
	  * <p>创建日期:2015-4-23 下午10:22:58。</p>
	 */
	public Node generateNextChildNode(Node node) {
		Node newNode = generateNextNodeForThisLevel(node);

		return newNode;
	}


	/**
	 * 
	  * <p>功能描述:获取父节点。</p>	
	  * @param node
	  * @return
	  * @since JDK1.6。
	  * <p>创建日期:2015-4-23 下午8:44:50。</p>
	 */
	public Node getParentNode(Node node) {
		for (Node n : nodeList) {
			if (node.getParentId() == n.getId()) {
				return n;
			}
		}
		return node;
	}

	/**
	  * 
	  * <p>功能描述:生成节点路径。</p>	
	  * @param node
	  * @return
	  * @since JDK1.6。
	  * <p>创建日期:2015-4-23 下午7:42:45。</p>
	  * <p>更新日期:[日期YYYY-MM-DD][变更描述]。</p>
	  */
	public void generateNodeText(Node node, String text) {

		if (node == null || "0".equals(node.getId())) {
			return;
		}
		
		Node pNode = getParentNode(node);

		if (!"0".equals(pNode.getId())) {
			text = pNode.getText() + separator + text;
		}

		node.setText(text);
	}

	/**
	 * 
	  * <p>功能描述:遍历所有树节点。</p>	
	  * @param node
	  * @since JDK1.6。
	  * <p>创建日期:2015-4-24 上午9:39:13。</p>
	  * <p>更新日期:[日期YYYY-MM-DD][变更描述]。</p>
	 */
	public void traverseNodeList(Node node) {
		if(node==null){
			node = getRoot(nodeList);
		}
		List<Node> childNodes = getChildNodes(node);
		System.out.println(node.getText());
		if (childNodes.size() > 0) {
			for (Node n : childNodes) {
				traverseNodeList(n);
			}
		}
	}
	public static void main(String[] args) {
		Number number = new SerialNumber();
		NumberTree treeNode = new NumberTree(".", number);

		addSomeNodes(treeNode);
		treeNode.traverseNodeList(null);
	}

	/**
	 * 
	  * <p>功能描述:获取根节点。</p>	
	  * @param nodeList
	  * @return
	  * author zhangxl 
	  * @since JDK1.6。
	  * <p>创建日期:2015-5-17 下午6:09:23。</p>
	 */
	public Node getRoot(List<Node> nodeList) {
		Node root = null;
		if (nodeList.size() <= 0 || (root = getNodeById(nodeList, "0")) == null) {
			root = createRoot();
			nodeList.add(root);
		}
		return root;
	}

	private Node getNodeById(List<Node> nodeList, String id) {
		Node node = null;
		if(id!=null){
			for (Node n : nodeList) {
				if (id.equals(n.getId())) {
					node = n;
					break;
				}
			}
		}
		return node;
	}

	private Node createRoot() {
		Node root = new Node("0", number.rootNumber(), "-1", 0);
		root.setText("0");
		return root;
	}
	
	/**
	 * 
	  * <p>功能描述:测试添加节点。</p>	
	  * @return
	  * @since JDK1.6。
	  * <p>创建日期:2015-4-24 上午10:53:22。</p>
	  * <p>更新日期:[日期YYYY-MM-DD][变更描述]。</p>
	 */
	private static Node addSomeNodes(NumberTree tree) {
		Node root = tree.getRoot(tree.nodeList);
		Node node1 = getNextNode(tree, root);//1
		Node node2 = getNextNode(tree, root);//2
		Node node3 = getNextNode(tree, root);//3
		Node node11 = getNextNode(tree, node1);//1.1
		Node node12 = getNextNode(tree, node1);//1.2
		Node node21 = getNextNode(tree, node2);//2.1
		Node node211 = getNextNode(tree, node21);//2.1.1
		Node node212 = getNextNode(tree, node21);//2.1.2
		Node node22 = getNextNode(tree, node2);//2.2
		Node node221 = getNextNode(tree, node22);//2.2.1
		Node node31 = getNextNode(tree, node3);
		Node node32 = getNextNode(tree, node3);
		Node node311 = getNextNode(tree, node31);
		Node node3111 = getNextNode(tree, node311);
		return root;
	}
	
	public static Node getNextNode(NumberTree tree, Node pNode) {
		Node node = tree.generateNextChildNode(pNode);
		if (node != null) {
			tree.nodeList.add(node);
		}
		return node;
	}
}

getNextNode(NumberTree tree, Node pNode)
该方法设计成静态方法,是为了在freemarker中调用方便.把NumberTree注册到freemarker中,就可以实现随意调用了.

dataMap.put("numberTree", FtlUtil.getHelperClass("com.report.bctcms.number.NumberTree"));

public class FtlUtil {
	public static TemplateHashModel useStaticPackage(String packageName) {
		TemplateHashModel fileStatics = null;
		try {
			BeansWrapper wrapper = BeansWrapper.getDefaultInstance();
			TemplateHashModel staticModels = wrapper.getStaticModels();
			fileStatics = (TemplateHashModel) staticModels.get(packageName);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return fileStatics;
	}

	public static TemplateHashModel getHelperClass(String clazz) {
		TemplateHashModel useStaticPackage = FtlUtil.useStaticPackage(clazz);
		return useStaticPackage;
	}
}

freemarker代码:

<#assign numberTree = root.numberTree />--注册的类
<#assign numberTreeObj = root.numberTreeObj />--当前的操作对象
<#assign rootNode = root.rootNode /><span style="font-family: Arial, Helvetica, sans-serif;">--从进入freemarker开始的其实节点</span>
<#assign num1 = numberTree.getNextNode(numberTreeObj,rootNode)/>--生成的标题对象(Node)

不足之处:

1,暂时只支持生成子节点的编号,不支持兄弟节点编号

2,生成一个编号对象需要的依赖比较多,稍显繁琐,但根据目前的需求只能如此




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值