一个简单的格式化信函生成器
? ? ? ? 童鞋們都應該見過各種各樣的請柬咯, 請柬上面通常是一個模板,然后填上被邀請人及相關信息,在 Word 里面稱之為 “郵件合并”特性。 今天,我們就來實現一個簡單的格式化信函生成器。 我們將要做的東西, 包括一個非常簡單的學生選課數據庫,以及簡單的模板, 利用數據庫中的記錄及模板生成格式化的通知信息。 關于C語言的實現, 請參考 《編程珠璣I》(第二版) 的第三章第二節。
? ? ? ? 別看這個東西簡單, 其中也蘊涵了不變和變化的部分。 不變是信息模板內容, 變化部分是數據庫中的記錄信息, 所要做的,就是將不變和變化隔離開來。 基本的設計思想如下:
? ? ? ? 1. ?一個非常簡單的學生選課數據庫, 包括學生信息表 students , 課程信息表 courses, 學生選課信息表 stus_cours;?
? ? ? ? 2. ?一個JDBC 實用工具類 JDBCUtil , 主要是從數據庫中檢索記錄, 并將其轉換為相應的記錄對象 DBRecord;?
? ? ? ? 3. ?記錄對象 DBRecord: 包含一個 String[] 數組, 用來存儲每條記錄中的數據項,一個 String 對應一條基本數據項。
? ? ? ? 4. ?模板信息接口: interface Template , 包含一個 getText() 的方法聲明;
? ? ? ? 5. ?兩個模板實現: 課程開設信息 CourseInfoTemplate 及 學生選課信息 CourseChosenTemplate
? ? ? ? 6. ?格式化信函生成器 FormattedLetter : 根據數據庫記錄及模板生成格式化通知
? ? ? ? 因為這個東西并不復雜, ?這里就不講解太多了, 相信童鞋們看過代碼之后很快就會明白的。下面給出代碼實現:
? ? ? ? ### course.sql
############################################## # course.sql: 建立一個簡單的學生選課數據庫 # NOTE: 必須保存為 utf-8 格式(文件 - 另存為), # 以保證在命令行下執行該文件能夠順利插入中文 ############################################################################################ # how to exec sql file # mysql -u root -p < /your_path/course.sql # Enter password: [input your root password] ############################################## # 或者使用 root 登錄 mysql, # 然后復制所有語句在 mysql 中執行。 ################################################################################### # mysql statement: ######################################CREATE USER 'course6'@'localhost' IDENTIFIED BY 'course6'; CREATE DATABASE course; grant all on course.* to 'course6'@'localhost';#####################################USE course;CREATE TABLE students ( id INT NOT NULL AUTO_INCREMENT, stuName varchar(12) NOT NULL, PRIMARY KEY(id)) ;CREATE TABLE courses (id INT NOT NULL AUTO_INCREMENT, cName varchar(15) NOT NULL, cTime int NOT NULL, note varchar(30),PRIMARY KEY(id)) ;CREATE table stus_cours ( stu_id int NOT NULL, cour_id int NOT NULL, sch_term varchar(5) NOT NULL, PRIMARY KEY(stu_id, cour_id)); alter table stus_cours add constraint stuCons foreign key(stu_id) references students(id); alter table stus_cours add constraint courCons foreign key(cour_id) references courses(id);desc courses;desc students;desc stus_cours;insert into students values(10001, '小華');insert into students values(10002, '小明');insert into courses values(1001, '高數', 54, '');insert into courses values(1002, '大學英語', 81, '');insert into stus_cours values(10001, 1001, '2nd');insert into stus_cours values(10002, 1001, '2nd');insert into stus_cours values(10001, 1002, '1st');insert into stus_cours values(10002, 1002, '1st');SELECT * from students;SELECT * from courses;SELECT * from stus_cours;SELECT stuName , cName, cTime , sch_term FROM students, courses, stus_cours WHERE students.id = stus_cours.stu_id AND courses.id = stus_cours.cour_id;JDBCUtil.java
? ? ? ?
package javatech.JDBClearn;import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List;import com.mysql.jdbc.ResultSetMetaData; import com.mysql.jdbc.Statement;public class JDBCUtil {private static Connection conn;private static final String mysqlDriver = "com.mysql.jdbc.Driver";private static final String mysqlURL = "jdbc:mysql://localhost:3306/course";private static final String username = "course6";private static final String password = "course6";private JDBCUtil() { }public static Connection getConnection() throws SQLException, ClassNotFoundException { Class.forName(mysqlDriver);conn = DriverManager.getConnection(mysqlURL, username, password);return conn; }public static void printResult(ResultSet rs) throws SQLException{ResultSetMetaData rsmd = (ResultSetMetaData) rs.getMetaData();int colNum = rsmd.getColumnCount();while(rs.next()) {for (int i = 0; i < colNum; i++) System.out.printf(rs.getString(i+1) + " ");System.out.println();}}public static List<DBRecord> toRecords(ResultSet rs) throws SQLException {List<DBRecord> records = new ArrayList<DBRecord>();ResultSetMetaData rsmd = (ResultSetMetaData) rs.getMetaData();int colNum = rsmd.getColumnCount();while(rs.next()) {String[] datas = new String[colNum]; for (int i = 0; i < colNum; i++) datas[i] = rs.getString(i+1);records.add(new DBRecord(datas));}rs.close();conn.close();return records;}public static ResultSet getResultSet(String sqlString) throws SQLException, ClassNotFoundException{Connection conn = getConnection();Statement stm = (Statement) conn.createStatement(); ResultSet rs = stm.executeQuery(sqlString);return rs;}public static void main(String[] args) throws SQLException, ClassNotFoundException{String sqlString = "SELECT stuName, cName, cTime, sch_term " +"FROM students, courses, stus_cours " +"WHERE students.id = stu_id AND " +" courses.id = cour_id; ";ResultSet rs = getResultSet(sqlString);printResult(rs);rs.close();conn.close();}}? ? ? ? DBRecord.java
? ? ? ?
package javatech.JDBClearn;/*** DBRecord: 與數據庫中一條行記錄相對應的數據對象**/ public class DBRecord {// 將數據庫中檢索到的一條記錄轉化為字符串并存儲private String[] datas;public DBRecord(String[] datas) {this.datas = datas;}// 返回數據庫中一條記錄的第 index 個數據項public String getDataTerm(int index) {if (index < 0 || index > datas.length-1) {throw new ArrayIndexOutOfBoundsException("數組下標越界!");}return datas[index];}// 返回數據庫一條記錄所含的數據項的數目public int dataTermNum() {return datas.length;}public String toString() {StringBuilder sb = new StringBuilder("[DBRecord]: ");for (String s: datas) {sb.append(s);sb.append(' ');}sb.append('\n');return sb.toString();}}? ? ? ? ?FormattedLetter.java
? ? ? ? ?
package javatech.JDBClearn;import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List;public class FormattedLetter {/*** 用數據庫中每條記錄的數據項依序替換模板中的模板數據。* @param record 數據庫中的一條記錄* @param tpl 指定模板文件接口* @return 替換后的格式化信函*/public String formattedLetter(DBRecord record, Template tpl) {String text = tpl.getText();for (int i=0; i < record.dataTermNum(); i++) text = text.replaceAll("\\$" + (i+1), record.getDataTerm(i));return text;}/*** 批量生成格式化信函*/public List<String> batFormattedLetter(List<DBRecord> records, Template tpl){List<String> letters = new ArrayList<String>();for (DBRecord r: records) {letters.add(formattedLetter(r, tpl));}return letters;}/*** printList: 打印列表內容*/public static <T> void printList(List<T> list){System.out.println("List: [");for (T t: list) {System.out.println(t);}System.out.println("]");}public static void test(String sqlStmt, Template tpl) throws SQLException, ClassNotFoundException{ResultSet rs = JDBCUtil.getResultSet(sqlStmt);List<DBRecord> records = JDBCUtil.toRecords(rs);List<String> letters = new FormattedLetter().batFormattedLetter(records , tpl);System.out.println("Formatted letters: ");printList(letters);}public static void main(String[] args) throws SQLException, ClassNotFoundException{String courseInfoSql = "SELECT cName, cTime FROM courses";test(courseInfoSql, new CourseInfoTemplate());String courseChosenString = "SELECT stuName, cName, cTime, sch_term " +"FROM students, courses, stus_cours " +"WHERE students.id = stu_id AND " +" courses.id = cour_id; ";test(courseChosenString, new CourseChosenTemplate()); }}? ? ? ?? ? ?
? ? ? ? ? ?CourseInfoTemplate.java
? ? ? ? ?CourseChosenTemplate.java
? ? ? ? ?
package javatech.JDBClearn;public class CourseChosenTemplate implements Template {private String text = "$1 , 你好! 你所選修的課程是 $2, 共 $3 學時, 在 $4 上, 請勿錯過。 ";public String getText(){return text;}}? ? ? ?Template.java
? ? ? ??末記: 可以改進的地方
? ? ? ? ? 1. 使用 replaceAll 方法替換模板文件中的多個模板數據效率可能會有些低下, 有待改進;
? ? ? ? ? 2. 必須根據數據庫中檢索到的記錄的數據項順序及模板中定義的模板項依序對應地替換,而不能無序的任意替換;
? ? ? ? ? 3. 模板文件及格式化信函生成器還可以做得更靈活一點, 比如,添加輸入輸出流, 使之模板文件可以來自于各種輸入流而不是簡單的字符串, 格式化信息可以輸出到各種目標流中,而不僅僅是控制臺。
?
? ? ? ??
?
??
??
總結
以上是生活随笔為你收集整理的一个简单的格式化信函生成器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 微信公众号 隐藏菜单
- 下一篇: 美团开店宝Android pad,美团开