diff --git a/.gitignore b/.gitignore
index f1e9957cf..4b65de197 100644
--- a/.gitignore
+++ b/.gitignore
@@ -280,6 +280,9 @@ target
 liuxin/.DS_Store
 liuxin/src/.DS_Store
 
+students/*
+!students/785396327
+
 
 
 
diff --git a/students/785396327/first/ood/srp/ConfigParser.java b/students/785396327/first/ood/srp/ConfigParser.java
new file mode 100644
index 000000000..87e00e707
--- /dev/null
+++ b/students/785396327/first/ood/srp/ConfigParser.java
@@ -0,0 +1,9 @@
+package first.ood.srp;
+
+/**
+ * Created by william on 2017/6/14.
+ */
+public abstract class ConfigParser {
+
+   abstract void parseInfoFromConfig(Email email);
+}
diff --git a/students/785396327/first/ood/srp/Configuration.java b/students/785396327/first/ood/srp/Configuration.java
new file mode 100644
index 000000000..2d4130423
--- /dev/null
+++ b/students/785396327/first/ood/srp/Configuration.java
@@ -0,0 +1,28 @@
+package first.ood.srp;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class Configuration {
+
+    static Map<String, String> configurations = new HashMap<String, String>();
+
+
+    static {
+        configurations.put(ConfigurationKeys.SMTP_SERVER, "smtp.163.com");
+        configurations.put(ConfigurationKeys.ALT_SMTP_SERVER, "smtp1.163.com");
+        configurations.put(ConfigurationKeys.EMAIL_ADMIN, "admin@company.com");
+    }
+
+    /**
+     * 应该从配置文件读， 但是这里简化为直接从一个map 中去读
+     *
+     * @param key
+     * @return
+     */
+    public String getProperty(String key) {
+
+        return configurations.get(key);
+    }
+
+}
diff --git a/students/785396327/first/ood/srp/ConfigurationKeys.java b/students/785396327/first/ood/srp/ConfigurationKeys.java
new file mode 100644
index 000000000..28de2ced0
--- /dev/null
+++ b/students/785396327/first/ood/srp/ConfigurationKeys.java
@@ -0,0 +1,10 @@
+package first.ood.srp;
+
+public class ConfigurationKeys {
+
+	public static final String SMTP_SERVER = "smtp.server";
+	public static final String ALT_SMTP_SERVER = "alt.smtp.server";
+	public static final String EMAIL_ADMIN = "email.admin";
+	public static final String NAME_KEY = "NAME";
+	public static final String EMAIL_KEY = "EMAIL";
+}
diff --git a/students/785396327/first/ood/srp/DBParser.java b/students/785396327/first/ood/srp/DBParser.java
new file mode 100644
index 000000000..3e49e6abd
--- /dev/null
+++ b/students/785396327/first/ood/srp/DBParser.java
@@ -0,0 +1,24 @@
+package first.ood.srp;
+
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Created by william on 2017/6/14.
+ */
+public abstract class DBParser<T extends Email> {
+    protected String sql;
+    protected Object[] params;
+
+    protected DBParser(String sql, Object[] params) {
+        this.sql = sql;
+        this.params = params;
+    }
+
+    protected List<T> parseInfoFromDB(T email) {
+        List<HashMap<String, String>> data = DBUtil.query(sql, params);
+        return convertData(email, data);
+    }
+
+    abstract List<T> convertData(T email, List<HashMap<String, String>> data);
+}
diff --git a/students/785396327/first/ood/srp/DBUtil.java b/students/785396327/first/ood/srp/DBUtil.java
new file mode 100644
index 000000000..473b8b1ca
--- /dev/null
+++ b/students/785396327/first/ood/srp/DBUtil.java
@@ -0,0 +1,43 @@
+package first.ood.srp;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class DBUtil {
+
+    /**
+     * 应该从数据库读， 但是简化为直接生成。
+     *
+     * @param sql
+     * @return
+     */
+    public static List<HashMap<String, String>> query(String sql, Object[] params) {
+        formateSQL(sql, params);
+
+        List userList = new ArrayList();
+        for (int i = 1; i <= 3; i++) {
+            Map<String, String> userInfo = new HashMap();
+            userInfo.put("NAME", "User" + i);
+            userInfo.put("EMAIL", "aa@bb.com");
+            userList.add(userInfo);
+        }
+
+        return userList;
+    }
+
+    private static String formateSQL(String sql, Object[] params) {
+        if (StringUtils.isEmpty(sql))
+            throw new RuntimeException("empty sql");
+        String[] sqlFaction = sql.split("\\?");
+        if (sqlFaction.length - 1 != params.length)
+            throw new RuntimeException("wrong number of parameters");
+        for (int i = 0; i < params.length; i++) {
+            sql = sql.replaceFirst("\\?", "'" + params[i].toString() + "'");
+        }
+
+        return sql;
+    }
+
+}
diff --git a/students/785396327/first/ood/srp/Email.java b/students/785396327/first/ood/srp/Email.java
new file mode 100644
index 000000000..ebca19e57
--- /dev/null
+++ b/students/785396327/first/ood/srp/Email.java
@@ -0,0 +1,46 @@
+package first.ood.srp;
+
+/**
+ * Created by william on 2017/6/12.
+ */
+public class Email {
+    protected String smtpHost;
+    protected String altSmtpHost;
+    protected String fromAddress;
+    protected String toAddress;
+    protected String subject;
+    protected String message;
+
+    protected void setSMTPHost(String smtpHost) {
+        this.smtpHost = smtpHost;
+    }
+
+    protected void setAltSMTPHost(String altSmtpHost) {
+        this.altSmtpHost = altSmtpHost;
+
+    }
+
+    protected void setFromAddress(String fromAddress) {
+        this.fromAddress = fromAddress;
+    }
+
+    protected void setMessage(String message) {
+        this.message = message;
+    }
+
+    public String getToAddress() {
+        return toAddress;
+    }
+
+    public void setToAddress(String toAddress) {
+        this.toAddress = toAddress;
+    }
+
+    public String getSubject() {
+        return subject;
+    }
+
+    public void setSubject(String subject) {
+        this.subject = subject;
+    }
+}
diff --git a/students/785396327/first/ood/srp/EmailParser.java b/students/785396327/first/ood/srp/EmailParser.java
new file mode 100644
index 000000000..e6f422b52
--- /dev/null
+++ b/students/785396327/first/ood/srp/EmailParser.java
@@ -0,0 +1,26 @@
+package first.ood.srp;
+
+import java.util.List;
+
+/**
+ * Created by william on 2017/6/12.
+ */
+public class EmailParser {
+    private ConfigParser configParser;
+    private FileParser fileParser;
+    private DBParser dbParser;
+
+    public EmailParser(ConfigParser configParser,FileParser fileParser,DBParser dbParser) {
+        this.configParser = configParser;
+        this.fileParser = fileParser;
+        this.dbParser = dbParser;
+    }
+
+    public List<Email> parseEmailList() {
+        PromotionMail promotionMail = new PromotionMail();
+        configParser.parseInfoFromConfig(promotionMail);
+        fileParser.parseInfoFromFile(promotionMail);
+        return dbParser.parseInfoFromDB(promotionMail);
+    }
+
+}
diff --git a/students/785396327/first/ood/srp/FileParser.java b/students/785396327/first/ood/srp/FileParser.java
new file mode 100644
index 000000000..1f14c1138
--- /dev/null
+++ b/students/785396327/first/ood/srp/FileParser.java
@@ -0,0 +1,38 @@
+package first.ood.srp;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+
+/**
+ * Created by gongxun on 2017/6/12.
+ */
+public abstract class FileParser {
+    protected String[] data;
+
+    protected FileParser(String filePath) {
+        try {
+            if (StringUtils.isEmpty(filePath))
+                throw new RuntimeException("init file parser must contains a legal file");
+            readFile(filePath);
+        } catch (IOException e) {
+            throw new RuntimeException("parse file cause errors");
+        }
+    }
+
+    private void readFile(String filePath) throws IOException {
+        BufferedReader br = null;
+        try {
+            br = new BufferedReader(new FileReader(filePath));
+            String temp = br.readLine();
+            data = temp.split(" ");
+        } catch (IOException e) {
+            throw new IOException(e.getMessage());
+        } finally {
+            br.close();
+        }
+    }
+
+    protected abstract void parseInfoFromFile(Email email);
+
+}
diff --git a/students/785396327/first/ood/srp/MailSender.java b/students/785396327/first/ood/srp/MailSender.java
new file mode 100644
index 000000000..a2ed82db4
--- /dev/null
+++ b/students/785396327/first/ood/srp/MailSender.java
@@ -0,0 +1,33 @@
+package first.ood.srp;
+
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Created by william on 2017/6/12.
+ */
+public class MailSender<T extends Email> {
+
+    private void sendMail(Email mail, boolean isDebug) {
+        if (!StringUtils.isEmpty(mail.toAddress))
+            try {
+                MailUtil.sendEmail(
+                        mail.toAddress,
+                        mail.fromAddress,
+                        mail.subject,
+                        mail.message,
+                        StringUtils.isEmpty(mail.smtpHost) == true ? mail.smtpHost : mail.altSmtpHost,
+                        isDebug);
+            } catch (Exception e) {
+                System.out.println("通过备用 SMTP服务器发送邮件失败: " + e.getMessage());
+            }
+    }
+
+    public void sendMailList(List<T> mailList, boolean isDebug) {
+        if (mailList != null) {
+            for (Iterator<T> iterator = mailList.iterator(); iterator.hasNext(); ) {
+                sendMail(iterator.next(), isDebug);
+            }
+        }
+    }
+}
diff --git a/students/785396327/first/ood/srp/MailUtil.java b/students/785396327/first/ood/srp/MailUtil.java
new file mode 100644
index 000000000..2ec9de8c4
--- /dev/null
+++ b/students/785396327/first/ood/srp/MailUtil.java
@@ -0,0 +1,16 @@
+package first.ood.srp;
+
+public class MailUtil {
+
+	public static void sendEmail(String toAddress, String fromAddress, String subject, String message, String smtpHost,
+			boolean debug) {
+		//假装发了一封邮件
+		StringBuilder buffer = new StringBuilder();
+		buffer.append("From:").append(fromAddress).append("\n");
+		buffer.append("To:").append(toAddress).append("\n");
+		buffer.append("Subject:").append(subject).append("\n");
+		buffer.append("Content:").append(message).append("\n");
+		System.out.println(buffer.toString());
+		
+	}
+}
diff --git a/students/785396327/first/ood/srp/PromotionFileParser.java b/students/785396327/first/ood/srp/PromotionFileParser.java
new file mode 100644
index 000000000..1d57b8de2
--- /dev/null
+++ b/students/785396327/first/ood/srp/PromotionFileParser.java
@@ -0,0 +1,27 @@
+package first.ood.srp;
+
+/**
+ * Created by william on 2017/6/14.
+ */
+public class PromotionFileParser extends FileParser {
+
+
+    public PromotionFileParser(String filePath) {
+        super(filePath);
+    }
+
+    @Override
+    protected void parseInfoFromFile(Email email) {
+        PromotionMail promotionMail = (PromotionMail) email;
+        promotionMail.setProductID(parseProductID());
+        promotionMail.setProductDesc(parseProductDesc());
+    }
+
+    private String parseProductID() {
+        return super.data[0];
+    }
+
+    private String parseProductDesc() {
+        return super.data[1];
+    }
+}
diff --git a/students/785396327/first/ood/srp/PromotionMail.java b/students/785396327/first/ood/srp/PromotionMail.java
new file mode 100644
index 000000000..48096fa54
--- /dev/null
+++ b/students/785396327/first/ood/srp/PromotionMail.java
@@ -0,0 +1,22 @@
+package first.ood.srp;
+
+public class PromotionMail extends Email {
+    private String productID;
+    private String productDesc;
+
+    public void setProductID(String productID) {
+        this.productID = productID;
+    }
+
+    public String getproductID() {
+        return productID;
+    }
+
+    public void setProductDesc(String desc) {
+        this.productDesc = desc;
+    }
+
+    public String getProductDesc() {
+        return this.productDesc;
+    }
+}
diff --git a/students/785396327/first/ood/srp/PromotionMailConfigParser.java b/students/785396327/first/ood/srp/PromotionMailConfigParser.java
new file mode 100644
index 000000000..6fd8feb08
--- /dev/null
+++ b/students/785396327/first/ood/srp/PromotionMailConfigParser.java
@@ -0,0 +1,15 @@
+package first.ood.srp;
+
+/**
+ * Created by william on 2017/6/14.
+ */
+public class PromotionMailConfigParser extends ConfigParser {
+
+    @Override
+    void parseInfoFromConfig(Email email) {
+        Configuration configuration = new Configuration();
+        email.setSMTPHost(configuration.getProperty(ConfigurationKeys.SMTP_SERVER));
+        email.setFromAddress(configuration.getProperty(ConfigurationKeys.EMAIL_ADMIN));
+        email.setAltSMTPHost(configuration.getProperty(ConfigurationKeys.ALT_SMTP_SERVER));
+    }
+}
diff --git a/students/785396327/first/ood/srp/PromotionMailDBParser.java b/students/785396327/first/ood/srp/PromotionMailDBParser.java
new file mode 100644
index 000000000..55e740474
--- /dev/null
+++ b/students/785396327/first/ood/srp/PromotionMailDBParser.java
@@ -0,0 +1,48 @@
+package first.ood.srp;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Created by william on 2017/6/14.
+ */
+public class PromotionMailDBParser extends DBParser<PromotionMail> {
+
+    protected PromotionMailDBParser(String sql, Object[] params) {
+        super(sql, params);
+    }
+
+    /**
+     * 由于sql参数需要运行时提供所以重写parseInfoFromDB方法
+     * @param email
+     * @return
+     */
+    @Override
+    protected List<PromotionMail> parseInfoFromDB(PromotionMail email) {
+        List<HashMap<String, String>> data = DBUtil.query(super.sql, new Object[]{email.getproductID()});
+        return convertData(email, data);
+    }
+
+    @Override
+    List<PromotionMail> convertData(PromotionMail email, List<HashMap<String, String>> data) {
+        List<PromotionMail> mailList = new ArrayList<PromotionMail>();
+        for (HashMap<String, String> map : data) {
+            email.setToAddress(parseToAddress(map));
+            email.setMessage(parseMessage(map, email));
+            email.setSubject("您关注的产品降价了");
+            mailList.add(email);
+        }
+        return mailList;
+    }
+
+    private String parseMessage(HashMap<String, String> map, PromotionMail promotionMail) {
+        String name = map.get(ConfigurationKeys.NAME_KEY);
+        String message = "尊敬的 " + name + ", 您关注的产品 " + promotionMail.getProductDesc() + " 降价了，欢迎购买!";
+        return message;
+    }
+
+    private String parseToAddress(HashMap<String, String> map) {
+        return map.get(ConfigurationKeys.EMAIL_KEY);
+    }
+}
diff --git a/students/785396327/first/ood/srp/SendMailTest.java b/students/785396327/first/ood/srp/SendMailTest.java
new file mode 100644
index 000000000..2b54947c0
--- /dev/null
+++ b/students/785396327/first/ood/srp/SendMailTest.java
@@ -0,0 +1,24 @@
+package first.ood.srp;
+
+import java.util.List;
+
+/**
+ * Created by william on 2017/6/12.
+ */
+public class SendMailTest {
+
+    public static void main(String[] args) {
+        String sql = "Select name from subscriptions where product_id= ? and send_mail=1";
+        String filepath = "D:\\workspace\\IDEA\\homework\\coding2017_section2\\coding2017\\students\\785396327\\first\\ood\\srp\\product_promotion.txt";
+        boolean isDebug = false;
+
+        ConfigParser configParser = new PromotionMailConfigParser();
+        FileParser fileParser = new PromotionFileParser(filepath);
+        DBParser<PromotionMail> DBParser = new PromotionMailDBParser(sql, null);
+
+        EmailParser emailParser = new EmailParser(configParser, fileParser, DBParser);
+        List promotionMails = emailParser.parseEmailList();
+        MailSender<PromotionMail> mailSender = new MailSender();
+        mailSender.sendMailList(promotionMails, isDebug);
+    }
+}
diff --git a/students/785396327/first/ood/srp/StringUtils.java b/students/785396327/first/ood/srp/StringUtils.java
new file mode 100644
index 000000000..ec0483fa8
--- /dev/null
+++ b/students/785396327/first/ood/srp/StringUtils.java
@@ -0,0 +1,17 @@
+package first.ood.srp;
+
+/**
+ * Created by william on 2017/6/12.
+ */
+public class StringUtils {
+
+    /**
+     * 判断字符串是否为空
+     *
+     * @param str
+     * @return
+     */
+    public static boolean isEmpty(String str) {
+        return str == null || str.trim().isEmpty();
+    }
+}
diff --git a/students/785396327/first/ood/srp/product_promotion.txt b/students/785396327/first/ood/srp/product_promotion.txt
new file mode 100644
index 000000000..b7a974adb
--- /dev/null
+++ b/students/785396327/first/ood/srp/product_promotion.txt
@@ -0,0 +1,4 @@
+P8756 iPhone8
+P3946 XiaoMi10
+P8904 Oppo_R15
+P4955 Vivo_X20
\ No newline at end of file
