portal web service

Service.java 19KB

    package com.ekexiu.portal.question; import com.ekexiu.portal.notify.NotifyService; import com.ekexiu.portal.notify.NotifyType; import com.ekexiu.portal.util.SqlUtil; import org.jfw.apt.annotation.Autowrie; import org.jfw.apt.annotation.DefaultValue; import org.jfw.apt.web.annotation.Path; import org.jfw.apt.web.annotation.operate.Get; import org.jfw.apt.web.annotation.operate.Post; import org.jfw.apt.web.annotation.param.*; import org.jfw.util.ListUtil; import org.jfw.util.StringUtil; import org.jfw.util.exception.JfwBaseException; import org.jfw.util.jdbc.JdbcUtil; import org.jfw.util.jdbc.PreparedStatementConfig; import org.jfw.util.web.fileupload.Item; import org.jfw.util.web.fileupload.UploadItemIterator; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; @Path("/question") public class Service { private static final AtomicInteger FN_IDX = new AtomicInteger(1); @Autowrie private QuestionDao questionDao; @Autowrie private NotifyService notifyService; private File imgPath; public NotifyService getNotifyService() { return notifyService; } public void setNotifyService(NotifyService notifyService) { this.notifyService = notifyService; } public File getImgPath() { return imgPath; } public void setImgPath(File imgPath) { this.imgPath = imgPath; } public QuestionDao getQuestionDao() { return questionDao; } public void setQuestionDao(QuestionDao questionDao) { this.questionDao = questionDao; } /** * 上传文件 * * @param it * @return * @throws Exception */ @Path("/upload") @Post public List<UploadFile> upload(@Upload UploadItemIterator it) throws Exception { List<UploadFile> ret = new LinkedList<UploadFile>(); try { while (it.hasNext()) { Item item = it.next(); if (!item.isFormField()) { String name = normalizeFileName(item.getName()); int index = name.lastIndexOf('.'); String ext = index >= 0 ? name.substring(index + 1) : ""; ext = ext.trim(); long fileLen = 0; int len = 0; UploadFile uf = this.buildTargetFile(ext); uf.setName(name); File file = uf.getFn(); ret.add(uf); byte[] buf = new byte[8092]; OutputStream of = new FileOutputStream(file); try { InputStream in = item.getInputStream(); try { while ((len = in.read(buf)) >= 0) { if (len > 0) { of.write(buf, 0, len); fileLen += len; } } uf.setSize(fileLen); } finally { in.close(); } } finally { of.close(); } } } return ret; } catch (Exception e) { this.remove(ret); throw e; } finally { if (it != null) it.clean(); } } /** * 新增一提问 * * @param con * @param q * title 标题 ,cnt 描述 img 图片 以英文逗号分隔, keys 关键字 以英文逗号分隔 ,uid 用户ID * @return * @throws SQLException */ @Path() @Post public String save(@JdbcConn(true) Connection con, @RequestParam(fields = { @FieldParam(value = "title", valueClass = String.class), @FieldParam(value = "cnt", valueClass = String.class, required = false), @FieldParam(value = "img", valueClass = String.class, required = false), @FieldParam(value = "keys", valueClass = String.class), @FieldParam(value = "uid", valueClass = String.class) }) Question q) throws SQLException { String id = StringUtil.buildUUID(); q.setId(id); q.setReplyCount(0); q.setState("1"); List<String> kws = ListUtil.splitTrimExcludeEmpty(q.getKeys(), ','); if (kws.isEmpty()) throw new IllegalArgumentException("param keys invalid"); questionDao.insert(con, q); questionDao.insert(con, build(id, kws)); return id; } /** * 默认的邀请专家 * * @param con * @param id * 提问ID * @param uid * 本人ID * @param count * limit 查询 返回最后一条的 kws ,首次不传 * @param pid * limit 查询 返回最后一条的 id 首次可不传 * @param rows * limit查询返回的最大数据条数 * @return * @throws SQLException */ @Get @Path("/commendatoryPro") public List<Map<String, Object>> professor(@JdbcConn Connection con, final String id,final String uid, final @DefaultValue("Integer.MAX_VALUE") int count, final @DefaultValue("\"0\"") String pid, final @DefaultValue("Integer.MAX_VALUE") int rows) throws SQLException { return JdbcUtil.queryMaps(con, "select id, kws from(select id,count(1) kws from pro_key_word where id <> ? and kw in (select kw from qet_key_word where id =?) group by id ) t where kws<= ? and id >? order by kws desc,id asc limit ?", new PreparedStatementConfig() { @Override public void config(PreparedStatement ps) throws SQLException { ps.setString(1,uid); ps.setString(2, id); ps.setInt(3, count); ps.setString(4, pid); ps.setInt(5, rows); } }); } /** * 邀请专家回答提问 * * @param con * @param qid * 提问id * @param pid * 专家id(被邀请人) * @param uid * 操作人(邀请人 * @param uname * 操作人(邀请人)姓名 * @return * @throws SQLException * @throws JfwBaseException */ @Post @Path("/invite") public boolean invite(@JdbcConn(true) Connection con, String qid, String pid, String uid, String uname,@AfterCommit List<Runnable> runs) throws SQLException, JfwBaseException { Question q = questionDao.query(con, qid); if (q == null) { throw new JfwBaseException(50000, "question[" +qid + "] not found"); } QuestionInviteRec rec = new QuestionInviteRec(); rec.setUid(uid); rec.setPid(pid); rec.setQid(qid); try{ questionDao.insert(con,rec); }catch(SQLException e){ if(SqlUtil.unique(e)){ throw new JfwBaseException(50001, "duplicate invite"); } throw e; } this.notifyService.notify(con, pid, uid, uname, qid, q.getTitle(), NotifyType.INVITE_ANSWER, runs); return true; } @Get @Path("/invite") public List<QuestionInviteRec> queryInviteRec(@JdbcConn Connection con,String uid,String qid,String[] pid)throws SQLException{ return questionDao.queryInviteRec(con, qid, uid, pid); } /** * 回答一个提问 * * @param con * @param qid * 提问ID * @param cnt * 回答内容 * @param uid * 回答 人ID * @param uname * 回答人姓名 * @return * @throws SQLException * @throws JfwBaseException */ @Post @Path("/answer") public String answer(@JdbcConn(true) Connection con, String qid, String cnt, String uid, String uname, @AfterCommit List<Runnable> runs) throws SQLException, JfwBaseException { Question q = questionDao.query(con, qid); if (q == null) { throw new JfwBaseException(50000, "question[" + qid + "] not found"); } String id = StringUtil.buildUUID(); Answer a = new Answer(); a.setId(id); a.setAgree(0); a.setBallot(0); a.setCnt(cnt); a.setQid(qid); a.setState("1"); a.setUid(uid); try { questionDao.insert(con, a); } catch (SQLException e) { if (SqlUtil.unique(e)) { throw new JfwBaseException(50001, "duplicate answer"); } throw e; } questionDao.incQuestionReply(con, qid); notifyService.notify(con, q.getUid(), uid, uname, qid, q.getTitle(), NotifyType.ANSWER_QUESTION, runs); return id; } @Get @Path("/answer") public Answer answer(@JdbcConn Connection con,String id)throws SQLException{ return questionDao.queryAnswer(con, id); } @Get @Path("/answer/exists") public boolean existsAnswer(@JdbcConn Connection con,String uid,String qid)throws SQLException{ return null!=questionDao.answer(con, uid, qid); } /** * 修改一个回答 * * @param con * @param id * 回答ID * @param cnt * 回答内容 * @param uid * 用户ID * @param uname * 用户姓名 * @return * @throws SQLException */ @Post @Path("/answer/modify") public int answerUpdate(@JdbcConn(true) Connection con, String id, String cnt, String uid, String uname) throws SQLException { return questionDao.updateAnswer(con, id, cnt); } @Get @Path("/qo") public Question queryOne(@JdbcConn Connection con, String id) throws SQLException { return questionDao.query(con, id); } @Get @Path("/qm") public List<Question> query(@JdbcConn Connection con, String[] ids) throws SQLException { return questionDao.query(con, ids); } /** * 等您回答 1、只显示“发布中”的问题 按问题发布时间,由新到旧排序。 * * @param con * @param time * limit查询最后一条的createTime 首次不传 * @param id * limit查询最后一条的id 首次不传 * @param rows * limit查询最后一条的最大返回条数 * @return * @throws SQLException */ @Get @Path() public List<Question> query(@JdbcConn Connection con, @DefaultValue("\"99999999999999\"") String time, @DefaultValue("\"0\"") String id, @DefaultValue("10000000") int rows) throws SQLException { return questionDao.query(con, "1", null, time+id, rows); } /** * 我提出的 1、只显示“发布中”的问题 按问题发布时间,由新到旧排序。 * * @param con * @param uid * 用户ID * @param time * limit查询最后一条的createTime 首次不传 * @param id * limit查询最后一条的id 首次不传 * @param rows * limit查询最后一条的最大返回条数 * @return * @throws SQLException */ @Get @Path("/my") public List<Question> querySelf(@JdbcConn Connection con, String uid, @DefaultValue("\"99999999999999\"") String time, @DefaultValue("\"0\"") String id, @DefaultValue("10000000") int rows) throws SQLException { return questionDao.query(con, "1", uid, time+id, rows); } /** * 我关注的 1、只显示“发布中”的问题 按问题发布时间,由新到旧排序。 * * @param con * @param uid * 用户ID * @param time * limit查询最后一条的createTime 首次不传 * @param id * limit查询最后一条的id 首次不传 * @param rows * limit查询最后一条的最大返回条数 * @return * @throws SQLException */ @Get @Path("/watch") public List<Question> watch(@JdbcConn Connection con, String uid, @DefaultValue("\"99999999999999\"") String time, @DefaultValue("\"0\"") String id, @DefaultValue("10000000") int rows) throws SQLException { return questionDao.watch(con, uid, time+ id, rows); } /** * 我回答的 * * @param con * @param uid * 用户ID * @param time * limit查询最后一条的createTime 首次不传 * @param id * limit查询最后一条的id 首次不传 * @param rows * limit查询最后一条的最大返回条数 * @return * @throws SQLException */ @Get @Path("/answer/bySelf") public List<Answer> answerSelf(@JdbcConn Connection con, String uid, @DefaultValue("\"99999999999999\"") String time, @DefaultValue("\"0\"") String id, @DefaultValue("10000000") int rows) throws SQLException { return questionDao.answerSelf(con, uid, time+id, rows); } /** * 我关注的回答 * * @param con * @param uid * 用户ID * @param time * limit查询最后一条的createTime 首次不传 * @param id * limit查询最后一条的id 首次不传 * @param rows * limit查询最后一条的最大返回条数 * @return * @throws SQLException */ @Get @Path("/answer/byWatch") public List<Answer> answerWatch(@JdbcConn Connection con, String uid, @DefaultValue("\"99999999999999\"") String time, @DefaultValue("\"0\"") String id, @DefaultValue("10000000") int rows) throws SQLException { return questionDao.watchAnswer(con, uid, time+id, rows); } /** * 查询所有合法的回答(“发布中”的问题下的“发布中”的回答。); * 按最新回答时间,由新到旧排序 }) * @param con * @param time * @param id * @param rows * @return * @throws SQLException */ @Get @Path("/answer/byTime") public List<Answer> answerByTime(@JdbcConn Connection con,@DefaultValue("\"99999999999999\"") String time, @DefaultValue("\"0\"") String id, @DefaultValue("10000000") int rows) throws SQLException { return questionDao.answer(con, time+ id, rows); } /** * 指定提问的回答(按最新回答时间,由新到旧排序) * * @param con * @param qid * 提问ID * @param time * limit查询最后一条的createTime 首次不传 * @param id * limit查询最后一条的id 首次不传 * @param rows * limit查询最后一条的最大返回条数 * @return * @throws SQLException */ @Get @Path("/answer/qes/byTime") public List<Answer> byQes(@JdbcConn Connection con, String qid, @DefaultValue("\"99999999999999\"") String time, @DefaultValue("\"0\"") String id, @DefaultValue("10000000") int rows) throws SQLException { return questionDao.byQes(con, qid, time+id, rows); } /** * 指定提问的回答(按最新回答时间,由新到旧排序) * * @param con * @param qid * 提问ID * @param score * limit查询最后一条的score 首次不传 * @param id * limit查询最后一条的id 首次不传 * @param rows * limit查询最后一条的最大返回条数 * @return * @throws SQLException */ @Get @Path("/answer/qes/byScore") public List<SortedAnswwer> byQes(@JdbcConn Connection con, String qid, @DefaultValue("100000") int score, @DefaultValue("\"0\"") String id, @DefaultValue("10000000") int rows) throws SQLException { String p = "000000"+score; p = p.substring(p.length()-5)+id; return questionDao.byQesScore(con, qid, p, rows); } /** * 我的回答总点赞数 * * @param con * @param id * 用户ID * @return * @throws SQLException */ @Get @Path("/answer/my/agree/count") public int queryCountWithMyAnswer(@JdbcConn Connection con, final String id) throws SQLException { return JdbcUtil.queryInt(con, "SELECT COUNT(AGREE) FROM ANSWER WHERE UID=?", new PreparedStatementConfig() { @Override public void config(PreparedStatement ps) throws SQLException { ps.setString(1, id); } }, 0); } @Post @Path("/answer/agree") public void agree(@JdbcConn(true) Connection con, String id, String uid, String uname, @AfterCommit List<Runnable> runs) throws SQLException, JfwBaseException { Answer a = questionDao.queryAnswer(con, id); if (a == null) throw new JfwBaseException(50000, "answer[" + id + "] not found"); String qid = a.getQid(); Question q = questionDao.query(con, qid); if (q == null) throw new JfwBaseException(50000, "answer[" + id + "] ' question not found"); AnswerAgreeRec aar = new AnswerAgreeRec(); aar.setAid(id); aar.setUid(uid); aar.setFlag(true); boolean inserted = false; try { questionDao.insert(con, aar); inserted = true; } catch (SQLException e) { if (SqlUtil.unique(e)) { con.rollback(); } throw e; } if (inserted) { questionDao.update(con, id, 1, 1); } else { if (questionDao.agree(con, uid, id) > 0) { questionDao.update(con, id, 1, 0); } else { throw new JfwBaseException(50001, "duplicate answer agree"); } } notifyService.notify(con, a.getUid(), uid, uname, a.getId(), q.getTitle(), NotifyType.ACCEPT_ANSWER, runs); } @Get @Path("/answer/delete") public int logicDelete(@JdbcConn(true) Connection con,String id)throws SQLException{ return questionDao.logicDeleteAnswer(con, id); } @Post @Path("/answer/unAgree") public void unAgree(@JdbcConn(true) Connection con, String id, String uid, String uname, @AfterCommit List<Runnable> runs) throws SQLException, JfwBaseException { AnswerAgreeRec aar = new AnswerAgreeRec(); aar.setAid(id); aar.setUid(uid); aar.setFlag(false); boolean inserted = false; try { questionDao.insert(con, aar); inserted = true; } catch (SQLException e) { if (SqlUtil.unique(e)) { con.rollback(); } throw e; } if (inserted) { questionDao.update(con, id, 0, 1); } else { if (questionDao.unAgree(con, uid, id) > 0) { questionDao.update(con, id, -1, 0); } else { throw new JfwBaseException(50001, "duplicate answer unagree"); } } runs.add(new Runnable() { @Override public void run() { // TODO send notify } }); } public QetKeyWord[] build(String id, List<String> ss) { List<QetKeyWord> qKws = new ArrayList<>(ss.size()); for (String s : ss) { QetKeyWord kw = new QetKeyWord(); kw.setId(id); kw.setKw(s); qKws.add(kw); } return qKws.toArray(new QetKeyWord[qKws.size()]); } private void remove(List<UploadFile> list) { for (UploadFile file : list) { if (file.fn != null) file.fn.delete(); } } private UploadFile buildTargetFile(String ext) { StringBuilder sb = new StringBuilder(); sb.append(System.currentTimeMillis() / (1000 * 60 * 60 * 24)); File path = new File(this.imgPath, sb.toString()); if (!path.exists()) { synchronized (this) { if (!path.mkdirs()) throw new RuntimeException("mkdir error[" + path + "]"); FN_IDX.set(1); } } File file; do { String fn = FN_IDX.toString(); if (ext.isEmpty()) { file = new File(path, fn); } else { file = new File(path, fn + "." + ext); } FN_IDX.incrementAndGet(); } while (file.exists()); sb.append("/").append(file.getName()); UploadFile uf = new UploadFile(); uf.setFn(file); uf.setUri("/" + sb.toString()); return uf; } private String normalizeFileName(String fn) { int index = fn.indexOf('\\'); if (index >= 0) { fn = fn.substring(fn.lastIndexOf('\\') + 1); } index = fn.indexOf('/'); if (index >= 0) { fn = fn.substring(fn.lastIndexOf('/') + 1); } if (fn.length() == 0) throw new RuntimeException("invalid filename in Multipart/data request"); return fn; } public static class UploadFile { private String name; private String uri; private long size; private transient File fn; public File getFn() { return fn; } public void setFn(File fn) { this.fn = fn; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getUri() { return uri; } public void setUri(String uri) { this.uri = uri; } public long getSize() { return size; } public void setSize(long size) { this.size = size; } } }