kFeedback的更多介绍,请详见:
为什么开发kFeedback?
我像很多人一样,平时在闲暇之余做一些app,本人的作品主要有:
- 基于HTML5(jQuery Mobile)的企业通讯录,后来通过PhoneGap封装成apk,她的名字是kLink。目前使用人数350人;
- 黑龙江省交通违章信息推送系统,当你的车有交通违法信息时,会通过短信息第一时间通知车主;目前使用人数200人
- ... ...
今后还会有更多的app发布,我在想,好的app离不开用户的反馈,如果每一个app内嵌一个反馈(又叫留言)的话,反馈信息会分散,不利于作者进行统一的受理,所以才有了今天的kFeedback。kFeedback发布几天来,目前已有60人在试用,而我现在唯一担心的是,CloudFoundry能不能顶住?
废话不多说了,接下来我将kFeedback源码发出,感兴趣的朋友可以参考,由于系统比较简单,我想下边的源码可能也就会对初学者有点帮助,老手们不要“耻笑”。
kFeedback用了哪些技术?
jsp + html5 + BootStrap + jQuery + servlet + spring(jdbcTemplate) + mySQL
源码:
工程目录结构:
Action.java - 一个DispatchServlet
Demo.java - 一个基于HttpClient的测试类
Service.java - 封装了所有业务的Dao
index.jsp - 首页
main.jsp - 主页面
其它的没啥了,都是一些基本(标准)的配置文件。
我们从Service.java说起:
code:
package k.feedback;import java.security.MessageDigest;import java.util.HashMap;import java.util.Map;import javax.sql.DataSource;import org.apache.commons.mail.Email;import org.apache.commons.mail.EmailException;import org.apache.commons.mail.SimpleEmail;import org.springframework.jdbc.core.JdbcTemplate;import sun.misc.BASE64Encoder;import com.alibaba.fastjson.JSON;public class Service {final static int PAGE_QTY = 15;//每页展示的记录数private JdbcTemplate jdbcTemplate;public void setDataSource(DataSource dataSource) { this.jdbcTemplate = new JdbcTemplate(dataSource);}//初始化数据库表结构public void initDB(){ //drop table this.jdbcTemplate.execute("drop table IF EXISTS feedback"); this.jdbcTemplate.execute("drop table IF EXISTS app"); this.jdbcTemplate.execute("drop table IF EXISTS emp"); System.out.println("table drop ok"); StringBuilder emp = new StringBuilder(); emp.append(" CREATE TABLE emp( "); emp.append(" emp_id INT AUTO_INCREMENT, "); emp.append(" emp_email VARCHAR(128), "); emp.append(" emp_login_pwd VARCHAR(40), "); emp.append(" cdate TIMESTAMP, "); emp.append(" PRIMARY KEY (emp_id) "); emp.append(" )ENGINE=MYISAM "); StringBuilder app = new StringBuilder(); app.append(" CREATE TABLE app( "); app.append(" app_id INT AUTO_INCREMENT, "); app.append(" emp_id INT, "); app.append(" app_name VARCHAR(255), "); app.append(" app_desc VARCHAR(255), "); app.append(" app_token VARCHAR(40), "); app.append(" app_feedback_qty INT, "); app.append(" cdate TIMESTAMP, "); app.append(" PRIMARY KEY (app_id) "); app.append(" )ENGINE=MYISAM "); StringBuilder feedback = new StringBuilder(); feedback.append(" CREATE TABLE feedback( "); feedback.append(" feedback_id INT AUTO_INCREMENT, "); feedback.append(" emp_id INT, "); feedback.append(" app_id INT, "); feedback.append(" feedback_time TIMESTAMP, "); feedback.append(" feedback_info TEXT, "); feedback.append(" PRIMARY KEY (feedback_id) "); feedback.append(" )ENGINE=MYISAM "); String alter1 = "ALTER TABLE app ADD CONSTRAINT Refemp1 FOREIGN KEY (emp_id) REFERENCES emp(emp_id)"; String alter2 = "ALTER TABLE feedback ADD CONSTRAINT Refemp2 FOREIGN KEY (emp_id) REFERENCES emp(emp_id)"; String alter3 = "ALTER TABLE feedback ADD CONSTRAINT Refapp3 FOREIGN KEY (app_id) REFERENCES app(app_id)"; String createIndex4Emp = "create unique index idx_email_pwd on emp(emp_email,emp_login_pwd)"; String createIndex4App = "create unique index idx_token on app(app_token)"; this.jdbcTemplate.execute(emp.toString()); System.out.println("emp table created"); this.jdbcTemplate.execute(app.toString()); System.out.println("app table created"); this.jdbcTemplate.execute(feedback.toString()); System.out.println("feedback table created"); this.jdbcTemplate.execute(alter1); this.jdbcTemplate.execute(alter2); this.jdbcTemplate.execute(alter3); System.out.println("alter ok"); this.jdbcTemplate.execute(createIndex4Emp); this.jdbcTemplate.execute(createIndex4App); //创建默认账户 this.jdbcTemplate.update("INSERT INTO emp(emp_id,emp_email, emp_login_pwd ) values(1,?,?)","kzhou.hrb@gmail.com",encodeByMd5("111111")); System.out.println("kFeedback default user create ok"); //创建默认app this.jdbcTemplate.update("INSERT INTO app(app_id, emp_id, app_name, app_desc, app_token, app_feedback_qty) VALUES (1, 1, 'kFeedback-云反馈', '把你的产品反馈信息放在云上进行统一管理', 'kFeedback', 0)"); System.out.println("kFeedback default app create ok"); System.out.println("kFeedback db create ok");}//开发者注册public int reg(String email,String pwd){ //check email is exist int rv = this.jdbcTemplate.queryForInt("select count(*) from emp where emp_email = ?",email); if(rv == 0){ final String sql = "INSERT INTO emp(emp_email, emp_login_pwd ) values(?,?)"; return this.jdbcTemplate.update(sql,email,encodeByMd5(pwd)); }else{ return -999; }}//开发者修改密码public void updPwd(String empId,String newPwd){ final String sql = "update emp set emp_login_pwd = ? where emp_id = ?"; this.jdbcTemplate.update(sql,encodeByMd5(newPwd),empId);}//登录public String login(String email,String pwd){ final String sql = "select convert(emp_id,char) as emp_id,emp_email from emp where emp_email = ? and emp_login_pwd = ?"; Mapmap = new HashMap (); try { map = this.jdbcTemplate.queryForMap(sql,email,encodeByMd5(pwd)); map.put("result", "1"); return JSON.toJSONString(map); } catch (Exception e) { map.put("result", "0"); return JSON.toJSONString(map); }}//忘记密码public int forgetPwd(String email){ int rv = this.jdbcTemplate.queryForInt("select count(*) from emp where emp_email = ?",email); if(rv > 0){ //get new pwd String newPwd = this.getAppToken(); //upd emp pwd this.jdbcTemplate.update("update emp set emp_login_pwd = ? where emp_email = ?",encodeByMd5(newPwd),email); //send new pwd to email box StringBuilder msg = new StringBuilder(); msg.append("您好,您的kFeedback新密码为:").append(newPwd).append("\n\n").append("请重新登录;http://kfeedback.cloudfoundry.com"); this.sendEmail("来自kFeedback的密码重置邮件", email, msg.toString()); return 1;//成功 }else{ return 0; }}//新增产品-strings[0],strings[1],strings[2]=emp_id,app_name,app_descpublic void insApp(String...strings){ final String sql = "INSERT INTO app (emp_id, app_name, app_desc,app_feedback_qty, app_token) values(?,?,?,0,?)"; this.jdbcTemplate.update(sql,strings[0],strings[1],strings[2],getAppToken());}//删除产品public void delApp(String appId){ this.jdbcTemplate.update("delete from feedback where app_id = ?",appId); this.jdbcTemplate.update("delete from app where app_id = ?",appId);}//修改产品-strings[0],strings[1],strings[2]=app_name,app_desc,app_idpublic void updApp(String...strings){ final String sql = "update app set app_name=?,app_desc=? where app_id = ?"; this.jdbcTemplate.update(sql,strings[0],strings[1],strings[2]);}//查询产品public String getApp(String empId){ if(empId.equals("1")){ return JSON.toJSONString(this.jdbcTemplate.queryForList("select convert(app_id,char) as app_id,convert(emp_id,char) as emp_id,app_name,app_desc,app_token,convert(app_feedback_qty,char) as app_feedback_qty,convert(DATE_FORMAT(cdate,'%Y-%m-%d'),char) as cdate from app where emp_id = ?",empId)); }else{ return JSON.toJSONString(this.jdbcTemplate.queryForList("select convert(app_id,char) as app_id,convert(emp_id,char) as emp_id,app_name,app_desc,app_token,convert(app_feedback_qty,char) as app_feedback_qty,convert(DATE_FORMAT(cdate,'%Y-%m-%d'),char) as cdate from app where app_id = 1 union all select convert(app_id,char) as app_id,convert(emp_id,char) as emp_id,app_name,app_desc,app_token,convert(app_feedback_qty,char) as app_feedback_qty,convert(DATE_FORMAT(cdate,'%Y-%m-%d'),char) as cdate from app where emp_id = ?",empId)); }}//根据app_token反查app_idprivate Map getAppIdByToken(String token){ return this.jdbcTemplate.queryForMap("select convert(a.emp_id,char) as emp_id,convert(a.app_id,char) as app_id,e.emp_email,a.app_name from app a,emp e where a.emp_id = e.emp_id and a.app_token = ?",token);}//根据产品查询反馈信息public String getFeedback(String appId){ final String sql = "select convert(feedback_id,char) as feedback_id,convert(DATE_FORMAT(feedback_time,'%Y-%m-%d %H:%i:%s'),char) as feedback_time,feedback_info from feedback where app_id = ? order by feedback_time"; return JSON.toJSONString(this.jdbcTemplate.queryForList(sql,appId));}//删除反馈信息public void delFeedback(String feedbackId){ this.jdbcTemplate.update("delete from feedback where feedback_id = ?",feedbackId);}//开放api//新增反馈-strings[0],strings[1]]=app_token,feedback_infopublic void insFeedback(String...strings){ Map map = getAppIdByToken(strings[0]); String appId = map.get("app_id").toString(); final String sql = "INSERT INTO feedback (emp_id, app_id, feedback_info) values(?,?,?)"; this.jdbcTemplate.update(sql,map.get("emp_id"),appId,strings[1]); int feedbackQty = this.jdbcTemplate.queryForInt("select count(*) from feedback where app_id = ?",appId); this.jdbcTemplate.update("update app set app_feedback_qty=? where app_id = ?",feedbackQty,appId); //send email to app creator// StringBuilder msgTitle = new StringBuilder();// msgTitle.append("[来自kFeedback]:您的<").append(map.get("app_name").toString()).append(">App收到了新的反馈信息");// StringBuilder msg = new StringBuilder();// msg.append("[来自kFeedback]:您的<").append(map.get("app_name").toString()).append(">App收到了新的反馈信息").append("\n\n");// msg.append("新的反馈信息为:\n\n");// msg.append("TA说: ").append(strings[1]).append("\n\n").append("请访问;http://kfeedback.cloudfoundry.com").append("\n\n");// this.sendEmail(msgTitle.toString(), map.get("emp_email").toString(), msg.toString());}//开发api end//MD5private String encodeByMd5(String str) { MessageDigest md5; try { md5 = MessageDigest.getInstance("MD5"); BASE64Encoder base64en = new BASE64Encoder(); return base64en.encode(md5.digest(str.getBytes("utf-8"))); } catch (Exception e) { return str; }}//UUIDpublic String getAppToken(){ return System.currentTimeMillis()+"";}/** * 发送电子邮件 * @param title * @param emailAddr * @param msg * @throws EmailException */public void sendEmail(String title,String emailAddr,String msg){ try { Email email = new SimpleEmail(); email.setHostName("smtp.163.com"); email.setAuthentication("username", "password"); email.setFrom("kfeedback@163.com"); email.setSubject(title); email.setCharset("utf8"); email.setMsg(msg); email.addTo(emailAddr); email.send(); } catch (Exception e) { }}}
Action.java
code:
package k.feedback;import java.io.IOException;import javax.servlet.Servlet;import javax.servlet.ServletConfig;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.springframework.web.context.WebApplicationContext;import org.springframework.web.context.support.WebApplicationContextUtils;/** * Servlet implementation class Action */public class Action extends HttpServlet { private static final long serialVersionUID = 1L; private WebApplicationContext ctx = null; /** * @see HttpServlet#HttpServlet() */ public Action() { super(); } /** * @see Servlet#init(ServletConfig) */ public void init(ServletConfig config) throws ServletException { ctx = WebApplicationContextUtils.getWebApplicationContext(config.getServletContext()); } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// request.setCharacterEncoding("utf-8");// response.setCharacterEncoding("utf-8"); response.setHeader("Cache-Control", "no-cache"); response.setContentType("text/javascript"); Service service = (Service)ctx.getBean("service"); String callback = request.getParameter("callback"); String method = request.getParameter("m"); System.out.println("request method : " + method); if(method == null || method.trim().length() == 0){ response.getWriter().print("您的请求是非法的!"); }else{ if(method.equals("login")){ this.login(service,request,response,callback); }else if(method.equals("reg")){ this.reg(service,request,response,callback); }else if(method.equals("updPwd")){ this.updPwd(service,request,response,callback); }else if(method.equals("insApp")){ this.insApp(service,request,response,callback); }else if(method.equals("getApp")){ this.getApp(service,request,response,callback); }else if(method.equals("getFeedback")){ this.getFeedback(service,request,response,callback); }else if(method.equals("updApp")){ this.updApp(service,request,response,callback); }else if(method.equals("delApp")){ this.delApp(service,request,response,callback); }else if(method.equals("insFeedback")){ this.insFeedback(service,request,response,callback); } } } private void insFeedback(Service service, HttpServletRequest request,HttpServletResponse response, String callback) throws IOException { String token = request.getParameter("token"); String fb = request.getParameter("fb"); service.insFeedback(token,fb); response.getWriter().write(callback+"({\"result\" : \"1\"})"); } private void delApp(Service service, HttpServletRequest request,HttpServletResponse response, String callback) throws IOException { String appId =request.getParameter("appId"); service.delApp(appId); response.getWriter().write(callback+"({\"result\" : \"1\"})"); } private void updApp(Service service, HttpServletRequest request,HttpServletResponse response, String callback) throws IOException { String appId = request.getParameter("appId"); String appName = request.getParameter("appName"); String appDesc = request.getParameter("appDesc"); service.updApp(appName,appDesc,appId); response.getWriter().write(callback+"({\"result\" : \"1\"})"); } private void getFeedback(Service service, HttpServletRequest request,HttpServletResponse response, String callback) throws IOException { String appId = request.getParameter("appId"); String feedbackJson = service.getFeedback(appId); response.getWriter().write(callback+"("+feedbackJson+")"); } private void getApp(Service service, HttpServletRequest request,HttpServletResponse response, String callback) throws IOException { String empId = request.getParameter("empId"); String appJson = service.getApp(empId); response.getWriter().write(callback+"("+appJson+")"); } private void insApp(Service service, HttpServletRequest request,HttpServletResponse response, String callback) throws IOException { String empId = request.getParameter("empId"); String appName = request.getParameter("appName"); String appDesc = request.getParameter("appDesc"); service.insApp(empId,appName,appDesc); response.getWriter().write(callback+"({\"result\" : \"1\"})"); } private void updPwd(Service service, HttpServletRequest request,HttpServletResponse response, String callback) throws IOException { String empId = request.getParameter("empId"); String newPwd = request.getParameter("newPwd"); service.updPwd(empId, newPwd); response.getWriter().write(callback+"({\"result\" : \"1\"})"); } private void reg(Service service, HttpServletRequest request,HttpServletResponse response, String callback) throws IOException { String reg_email = request.getParameter("reg_email"); String reg_pwd = request.getParameter("reg_pwd"); int rv = service.reg(reg_email, reg_pwd); String output = callback+"({})"; if(rv == 1){ output = callback+"({\"result\" : \"1\"})";//reg成功 }else{ output = callback+"({\"result\" : \"0\"})";//reg失败 } response.getWriter().write(output); } private void login(Service service, HttpServletRequest request,HttpServletResponse response, String callback) throws IOException, ServletException { String email = request.getParameter("email"); String pwd = request.getParameter("pwd"); String loginInfo = service.login(email, pwd); response.getWriter().write(callback+"("+loginInfo+")"); }}index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>main.htmlkFeedback - 云反馈! kFeedback - 云反馈!
kFeedback是一个极简主义作品。
成功的产品离不开用户的反馈;kFeedback就是你的产品与最终用户之间的沟通桥梁。
kFeedback基本路径(Guide).
kFeedback使用指南
- 注册kFeedback账号(Reg account)
- 登录kFeedback(Login)
- 创建App(New app)
- 将系统生成的API嵌入到你的产品中(Embed kFeedback post-api in your projduct)
- OK
登录kFeedback系统(Login).
用您注册的电子邮件和密码登录系统
注册kFeedback账号(Register).
提供您的电子邮件及登录密码,瞬间即可完成注册
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>以上就是kFeedback的所有代码,配置文件比较简单,我就不提供了,如有需要,可给我留言。kFeedback - 云反馈! App反馈监控台(App feedback console)
为了方便大家学习和调试代码,我将完整的工程提供给大家,欢迎斧正