jiapeng 7 years ago
parent
commit
b27e24dc5f

+ 150 - 0
src/main/java/com/ekexiu/portal/leavemsg/LeaveMsg.java

@ -0,0 +1,150 @@
1
package com.ekexiu.portal.leavemsg;
2

3
import org.jfw.apt.orm.annotation.entry.Column;
4
import org.jfw.apt.orm.annotation.entry.PrimaryKey;
5
import org.jfw.apt.orm.annotation.entry.Table;
6
import org.jfw.apt.orm.core.enums.DE;
7

8
import com.ekexiu.portal.basepo.CreateTimeSupported;
9
import com.ekexiu.portal.basepo.ModifyTimeSupported;
10

11
@PrimaryKey("id")
12
@Table
13
public class LeaveMsg implements CreateTimeSupported,ModifyTimeSupported {
14

15
	private String id;
16
	private String cnt;
17
	private String refId;
18
	private String refType;
19
	private String top;
20
	private String parent;
21
	private String sender;
22
	private String reciver;
23
	private String createTime;
24
	private String modifyTime;
25
	private String state;
26
	private long  acceptCount;
27
	
28
	/**
29
	 * id
30
	 * @return
31
	 */
32
	@Column(DE.id_32)
33
	public String getId() {
34
		return id;
35
	}
36
	public void setId(String id) {
37
		this.id = id;
38
	}
39
	/**
40
	 * 留言内容
41
	 * @return
42
	 */
43
	@Column(DE.text_de)
44
	public String getCnt() {
45
		return cnt;
46
	}
47
	public void setCnt(String cnt) {
48
		this.cnt = cnt;
49
	}
50
	/**
51
	 * 留言主体ID ,  文章ID,论文ID,专利ID,提问ID
52
	 * @return
53
	 */
54
	@Column(DE.text_de)
55
	public String getRefId() {
56
		return refId;
57
	}
58
	public void setRefId(String refId) {
59
		this.refId = refId;
60
	}
61
	/**
62
	 * 留言主体类型,1:文章   2:论文   3:专利      4:提问
63
	 * @return
64
	 */
65
	@Column(DE.singleChar)
66
	public String getRefType() {
67
		return refType;
68
	}
69
	public void setRefType(String refType) {
70
		this.refType = refType;
71
	}
72
	/**
73
	 * 顶级留言ID
74
	 * @return
75
	 */
76
	@Column(DE.text_de)
77
	public String getTop() {
78
		return top;
79
	}
80
	public void setTop(String top) {
81
		this.top = top;
82
	}
83
	/**
84
	 * 上级留言ID
85
	 * @return
86
	 */
87
	@Column(DE.Text_de)
88
	public String getParent() {
89
		return parent;
90
	}
91
	public void setParent(String parent) {
92
		this.parent = parent;
93
	}
94
	/**
95
	 * 留言人ID
96
	 * @return
97
	 */
98
	@Column(DE.text_de)
99
	public String getSender() {
100
		return sender;
101
	}
102
	public void setSender(String sender) {
103
		this.sender = sender;
104
	}
105
	/**
106
	 * 上级留言的留言人ID
107
	 * @return
108
	 */
109
	@Column(DE.Text_de)
110
	public String getReciver() {
111
		return reciver;
112
	}
113
	public void setReciver(String reciver) {
114
		this.reciver = reciver;
115
	}
116
	public String getCreateTime() {
117
		return createTime;
118
	}
119
	public void setCreateTime(String createTime) {
120
		this.createTime = createTime;
121
	}
122
	public String getModifyTime() {
123
		return modifyTime;
124
	}
125
	public void setModifyTime(String modifyTime) {
126
		this.modifyTime = modifyTime;
127
	}
128
	/**
129
	 * 状态  1: 发布中   0 :删除的
130
	 * @return
131
	 */
132
	@Column(DE.singleChar)
133
	public String getState() {
134
		return state;
135
	}
136
	public void setState(String state) {
137
		this.state = state;
138
	}
139
	/**
140
	 * 留言语的点赞数
141
	 * @return
142
	 */
143
	@Column(DE.long_de)
144
	public long getAcceptCount() {
145
		return acceptCount;
146
	}
147
	public void setAcceptCount(long acceptCount) {
148
		this.acceptCount = acceptCount;
149
	}
150
}

+ 40 - 0
src/main/java/com/ekexiu/portal/leavemsg/LeaveMsgApRec.java

@ -0,0 +1,40 @@
1
package com.ekexiu.portal.leavemsg;
2

3
import org.jfw.apt.orm.annotation.entry.Column;
4
import org.jfw.apt.orm.annotation.entry.PrimaryKey;
5
import org.jfw.apt.orm.annotation.entry.Table;
6
import org.jfw.apt.orm.core.enums.DE;
7

8
import com.ekexiu.portal.basepo.CreateTimeSupported;
9

10
@Table
11
@PrimaryKey({"id","uid"})
12
public class LeaveMsgApRec  implements CreateTimeSupported{
13

14
	private String id;
15
	private String uid;
16
	private String createTime;
17

18
	@Column(DE.text_de)
19
	public String getId() {
20
		return id;
21
	}
22
	public void setId(String id) {
23
		this.id = id;
24
	}
25
	@Column(DE.text_de)
26
	public String getUid() {
27
		return uid;
28
	}
29
	public void setUid(String uid) {
30
		this.uid = uid;
31
	}
32
	@Override
33
	public String getCreateTime() {
34
		return this.createTime;
35
	}
36
	@Override
37
	public void setCreateTime(String createTime) {
38
		this.createTime = createTime;
39
	}
40
}

+ 80 - 0
src/main/java/com/ekexiu/portal/leavemsg/LeaveMsgDao.java

@ -0,0 +1,80 @@
1
package com.ekexiu.portal.leavemsg;
2

3
import java.sql.Connection;
4
import java.sql.SQLException;
5
import java.util.List;
6

7
import org.jfw.apt.annotation.DefaultValue;
8
import org.jfw.apt.annotation.Nullable;
9
import org.jfw.apt.orm.annotation.dao.Column;
10
import org.jfw.apt.orm.annotation.dao.DAO;
11
import org.jfw.apt.orm.annotation.dao.method.From;
12
import org.jfw.apt.orm.annotation.dao.method.IncludeFixSet;
13
import org.jfw.apt.orm.annotation.dao.method.OrderBy;
14
import org.jfw.apt.orm.annotation.dao.method.SetSentence;
15
import org.jfw.apt.orm.annotation.dao.method.Where;
16
import org.jfw.apt.orm.annotation.dao.method.operator.Insert;
17
import org.jfw.apt.orm.annotation.dao.method.operator.LimitSelect;
18
import org.jfw.apt.orm.annotation.dao.method.operator.QueryVal;
19
import org.jfw.apt.orm.annotation.dao.method.operator.SelectOne;
20
import org.jfw.apt.orm.annotation.dao.method.operator.UpdateWith;
21
import org.jfw.apt.orm.annotation.dao.param.GreaterThan;
22
import org.jfw.apt.orm.annotation.dao.param.GroupSqlColumn;
23
import org.jfw.apt.orm.annotation.dao.param.GtEq;
24
import org.jfw.apt.orm.core.defaultImpl.IntHandler;
25
import org.jfw.apt.orm.core.defaultImpl.StringHandler;
26

27
@DAO
28
public interface LeaveMsgDao {
29

30
	@Insert
31
	int insert(Connection con, LeaveMsg msg) throws SQLException;
32

33
	@UpdateWith
34
	@From(LeaveMsg.class)
35
	@SetSentence("STATE = '0'")
36
	@Where("STATE = '1' ")
37
	@IncludeFixSet
38
	int logicDelete(Connection con, String id) throws SQLException;
39

40
	@UpdateWith
41
	@From(LeaveMsg.class)
42
	@SetSentence("ACCEPT_COUNT = ACCEPT_COUNT + 1")
43
	@IncludeFixSet
44
	int incAccept(Connection con, String id) throws SQLException;
45

46
	@LimitSelect
47
	@Where("STATE='1'")
48
	@OrderBy("ORDER BY GREATE_TIME ASC,ID ASC")
49
	List<LeaveMsg> query(Connection con, String refId, String refType, @GtEq String createTime, @GreaterThan String id, int rows) throws SQLException;
50

51
	@Nullable
52
	@SelectOne
53
	LeaveMsg query(Connection con, String id) throws SQLException;
54

55
	@Insert
56
	int insert(Connection con, LeaveMsgApRec rec) throws SQLException;
57

58
	@Nullable
59
	@SelectOne
60
	LeaveMsgApRec queryAcceptRec(Connection con, String id, String uid) throws SQLException;
61

62
	@LimitSelect
63
	@OrderBy("ORDER BY GREATE_TIME ASC,ID ASC")
64
	List<LeaveMsg> queryWithParent(Connection con, String parent, @GtEq String createTime, @GreaterThan String id, int rows) throws SQLException;
65

66
	@LimitSelect
67
	@OrderBy("ORDER BY GREATE_TIME ASC,ID ASC")
68
	List<LeaveMsg> queryWithTop(Connection con, String top,
69
			@GroupSqlColumn(handlerClass = StringHandler.class, isAnd = false, value = { "SENDER=?", "RECIVER=?" }, force = true) String sid,
70
			@GroupSqlColumn(handlerClass = StringHandler.class, isAnd = false, value = { "SENDER=?", "RECIVER=?" }, force = true) String rid,
71
			@GtEq String createTime, @GreaterThan String id, int rows) throws SQLException;
72

73
	@QueryVal
74
	@From(LeaveMsg.class)
75
	@DefaultValue("0")
76
	@Column(value="COUNT(ID)",handlerClass=IntHandler.class)
77
	int queryCount(Connection con,String refType,String refId) throws SQLException;
78
	
79
	
80
}

+ 315 - 0
src/main/java/com/ekexiu/portal/leavemsg/Service.java

@ -0,0 +1,315 @@
1
package com.ekexiu.portal.leavemsg;
2

3
import java.sql.Connection;
4
import java.sql.PreparedStatement;
5
import java.sql.SQLException;
6
import java.util.List;
7
import java.util.Map;
8

9
import org.jfw.apt.annotation.Autowrie;
10
import org.jfw.apt.annotation.DefaultValue;
11
import org.jfw.apt.annotation.Nullable;
12
import org.jfw.apt.web.annotation.Path;
13
import org.jfw.apt.web.annotation.operate.Get;
14
import org.jfw.apt.web.annotation.operate.Post;
15
import org.jfw.apt.web.annotation.param.AfterCommit;
16
import org.jfw.apt.web.annotation.param.FieldParam;
17
import org.jfw.apt.web.annotation.param.JdbcConn;
18
import org.jfw.apt.web.annotation.param.RequestParam;
19
import org.jfw.util.StringUtil;
20
import org.jfw.util.exception.JfwBaseException;
21
import org.jfw.util.jdbc.JdbcUtil;
22
import org.jfw.util.jdbc.PreparedStatementConfig;
23

24
@Path("/leavemsg")
25
public class Service {
26
	@Autowrie
27
	private LeaveMsgDao leaveMsgDao;
28

29
	public LeaveMsgDao getLeaveMsgDao() {
30
		return leaveMsgDao;
31
	}
32

33
	public void setLeaveMsgDao(LeaveMsgDao leaveMsgDao) {
34
		this.leaveMsgDao = leaveMsgDao;
35
	}
36

37
	public String getSubjectTitle(Connection con, String type, String id) throws SQLException {
38
		return null;
39
	}
40

41
	/**
42
	 * 新增一顶级留言
43
	 * 
44
	 * @param con
45
	 * @param msg
46
	 *            cnt
47
	 * @param title
48
	 *            文章标题 论文标题 专利标题 提问
49
	 * @param uname
50
	 *            发送人名称
51
	 * @param runs
52
	 * @return
53
	 * @throws SQLException
54
	 */
55
	@Path()
56
	@Post
57
	public String save(@JdbcConn(true) Connection con,
58
			@RequestParam(fields = { @FieldParam(value = "cnt", valueClass = String.class), @FieldParam(value = "refId", valueClass = String.class),
59
					@FieldParam(value = "refType", valueClass = String.class), @FieldParam(value = "sender", valueClass = String.class) }) LeaveMsg msg,
60
			String title, String uname, @AfterCommit List<Runnable> runs) throws SQLException {
61

62
		String id = StringUtil.buildUUID();
63
		msg.setId(id);
64
		msg.setTop(id);
65
		msg.setState("1");
66
		msg.setParent(null);
67
		msg.setAcceptCount(0);
68
		runs.add(new Runnable() {
69
			@Override
70
			public void run() {
71
				// TODO: send notify
72
			}
73
		});
74
		leaveMsgDao.insert(con, msg);
75
		return id;
76
	}
77

78
	/**
79
	 * 回复留言
80
	 * 
81
	 * @param con
82
	 * @param cnt
83
	 *            留言内容
84
	 * @param id
85
	 *            被回复留言ID
86
	 * @param uid
87
	 *            用户ID
88
	 * @param title
89
	 *            留言主体 文章标题 论文标题 专利标题 提问
90
	 * @param uname
91
	 *            用户姓名
92
	 * @param runs
93
	 * @return
94
	 * @throws SQLException
95
	 * @throws JfwBaseException
96
	 */
97
	@Path("/reply")
98
	@Post
99
	public String reply(@JdbcConn(true) Connection con, String cnt, String id, String uid, @Nullable String title, String uname,
100
			@AfterCommit List<Runnable> runs) throws SQLException, JfwBaseException {
101
		final LeaveMsg msg = leaveMsgDao.query(con, id);
102
		if (msg == null)
103
			throw new JfwBaseException(50000, "leave message[id:" + id + "] not found");
104
		if (msg.getSender().equals(uid)) {
105
			throw new JfwBaseException(50001, "can't reply self");
106
		}
107
		String nid = StringUtil.buildUUID();
108
		msg.setParent(id);
109
		msg.setReciver(msg.getSender());
110
		msg.setSender(uid);
111
		msg.setState("1");
112
		msg.setCnt(cnt);
113
		msg.setId(nid);
114
		msg.setAcceptCount(0);
115
		if (title == null) {
116
			title = this.getSubjectTitle(con, msg.getRefType(), msg.getRefId());
117
			if (title == null || title.isEmpty()) {
118
				title = "<<丢失的数据>>";
119
			}
120
		}
121
		runs.add(new Runnable() {
122
			@Override
123
			public void run() {
124
				// TODO: send notify
125
			}
126
		});
127
		leaveMsgDao.insert(con, msg);
128
		return nid;
129
	}
130

131
	/**
132
	 * 查询某主体下的留言
133
	 * 
134
	 * @param con
135
	 * @param stype
136
	 *            主体类型 1:文章 2:论文 3:专利 4:提问
137
	 * @param sid
138
	 *            留言主体ID , 文章ID,论文ID,专利ID,提问ID
139
	 * @param time
140
	 *            留言时间 time > createTime
141
	 * @param id
142
	 *            留言ID time > createTime && id >leaveMsg.id
143
	 * @param rows
144
	 *            返回的最大条数
145
	 * @return
146
	 * @throws SQLException
147
	 */
148
	@Get
149
	@Path("/subject")
150
	public List<LeaveMsg> query(@JdbcConn Connection con, String stype, String sid, @DefaultValue("\"0\"") String time, @DefaultValue("\"0\"") String id,
151
			int rows) throws SQLException {
152
		return leaveMsgDao.query(con, sid, stype, time, id, rows);
153
	}
154

155
	@Get
156
	@Path("/count")
157
	public int query(@JdbcConn Connection con, String stype, String sid) throws SQLException {
158
		return leaveMsgDao.queryCount(con, stype, sid);
159
	}
160

161
	@Get
162
	@Path("/counts")
163
	public List<Map<String, Object>> query(@JdbcConn Connection con, final String stype, final String[] ids) throws SQLException {
164
		StringBuilder sb = new StringBuilder();
165
		sb.append("SELECT REF_ID rid,COUNT(1) num FROM LEAVE_MSG WHERE REF_TYPE =? AND REF_ID IN (?");
166
		for (int i = 1; i < ids.length; ++i) {
167
			sb.append(",?");
168
		}
169
		sb.append(") GROUP BY rid");
170

171
		return JdbcUtil.queryMaps(con, sb.toString(), new PreparedStatementConfig() {
172

173
			@Override
174
			public void config(PreparedStatement ps) throws SQLException {
175
				int idx = 1;
176
				ps.setString(idx++, stype);
177
				for (int i = 0; i < ids.length; ++i) {
178
					ps.setString(idx++, ids[i]);
179
				}
180
			}
181
		});
182
	}
183

184
	/**
185
	 * 删除留言
186
	 * 
187
	 * @param con
188
	 * @param id
189
	 *            留言ID
190
	 * @return
191
	 * @throws SQLException
192
	 */
193
	@Get
194
	@Path("/del")
195
	public int delete(@JdbcConn(true) Connection con, String id) throws SQLException {
196
		return leaveMsgDao.logicDelete(con, id);
197
	}
198

199
	/**
200
	 * 点赞留言
201
	 * 
202
	 * @param con
203
	 * @param id
204
	 *            留言ID
205
	 * @param uid
206
	 *            点赞用户ID * @param uname 点赞用户姓名
207
	 * @param runs
208
	 * @throws SQLException
209
	 * @throws JfwBaseException
210
	 */
211
	@Post
212
	@Path("/accept")
213
	public void accept(@JdbcConn(true) Connection con, String id, String uid, String uname, @AfterCommit List<Runnable> runs)
214
			throws SQLException, JfwBaseException {
215
		LeaveMsg msg = leaveMsgDao.query(con, id);
216
		if (msg == null) {
217
			throw new JfwBaseException(50000, "leave message[id:" + id + "] not found");
218
		}
219
		LeaveMsgApRec lmar = new LeaveMsgApRec();
220
		lmar.setId(id);
221
		lmar.setUid(uid);
222
		try {
223
			leaveMsgDao.insert(con, lmar);
224
		} catch (SQLException e) {
225
			if ("23505".equals(e.getSQLState())) {
226
				con.rollback();
227
				throw new JfwBaseException(50001, "leave message  duplicate accept");
228
			}
229
			throw e;
230
		}
231
		if (leaveMsgDao.incAccept(con, id) > 0) {
232
			runs.add(new Runnable() {
233
				@Override
234
				public void run() {
235
					// TODO: send notify
236
				}
237
			});
238
		}
239
	}
240

241
	/**
242
	 * 是否对指定留言点过赞
243
	 * 
244
	 * @param con
245
	 * @param id
246
	 *            留言 ID
247
	 * @param uid
248
	 *            用户ID
249
	 * @return
250
	 * @throws SQLException
251
	 */
252
	@Get
253
	@Path("/accept")
254
	public boolean accept(@JdbcConn Connection con, String id, String uid) throws SQLException {
255
		return null != leaveMsgDao.queryAcceptRec(con, id, uid);
256
	}
257

258
	/**
259
	 * 查贸询一个指定的留言
260
	 * 
261
	 * @param con
262
	 * @param id
263
	 *            留言ID
264
	 * @return
265
	 * @throws SQLException
266
	 */
267
	@Get
268
	@Path("/qo")
269
	public LeaveMsg query(@JdbcConn Connection con, String id) throws SQLException {
270
		return leaveMsgDao.query(con, id);
271
	}
272

273
	// @Get
274
	// @Path("/parent")
275
	// public List<LeaveMsg> parent(@JdbcConn Connection con, String parent,
276
	// @DefaultValue("\"0\"") String time, @DefaultValue("\"0\"") String id,
277
	// @DefaultValue("10") int rows) throws SQLException {
278
	// return leaveMsgDao.queryWithParent(con, parent, time, id, rows);
279
	// }
280
	//
281
	// @Get
282
	// @Path("/top")
283
	// public List<LeaveMsg> top(@JdbcConn Connection con, String top, String
284
	// sid, String rid, @DefaultValue("\"0\"") String time,
285
	// @DefaultValue("\"0\"") String id,
286
	// @DefaultValue("10") int rows) throws SQLException {
287
	// return leaveMsgDao.queryWithTop(con, top, sid, rid, time, id, rows);
288
	// }
289
	/**
290
	 * 留言对话框
291
	 * 
292
	 * @param con
293
	 * @param id
294
	 *            留言ID
295
	 * @return
296
	 * @throws SQLException
297
	 * @throws JfwBaseException
298
	 */
299
	@Get
300
	@Path("/dialog")
301
	public List<LeaveMsg> dialog(@JdbcConn Connection con, String id) throws SQLException, JfwBaseException {
302
		List<LeaveMsg> ret = null;
303
		LeaveMsg msg = leaveMsgDao.query(con, id);
304
		if (msg == null)
305
			throw new JfwBaseException(50000, "leave message[id:" + id + "] not found");
306
		if (msg.getId().equals(msg.getTop())) {
307
			ret = leaveMsgDao.queryWithParent(con, msg.getId(), "0", "0", Integer.MAX_VALUE);
308
			ret.add(0, msg);
309
		} else {
310
			ret = leaveMsgDao.queryWithTop(con, msg.getId(), msg.getSender(), msg.getReciver(), "0", "0", Integer.MAX_VALUE);
311
		}
312
		return ret;
313
	}
314

315
}

+ 119 - 0
src/main/java/com/ekexiu/portal/question/Answer.java

@ -0,0 +1,119 @@
1
package com.ekexiu.portal.question;
2

3
import org.jfw.apt.orm.annotation.entry.Column;
4
import org.jfw.apt.orm.annotation.entry.PrimaryKey;
5
import org.jfw.apt.orm.annotation.entry.Table;
6
import org.jfw.apt.orm.annotation.entry.Unique;
7
import org.jfw.apt.orm.annotation.entry.Uniques;
8
import org.jfw.apt.orm.core.enums.DE;
9

10
import com.ekexiu.portal.basepo.CreateTimeSupported;
11
import com.ekexiu.portal.basepo.ModifyTimeSupported;
12
@PrimaryKey("id")
13
@Uniques({@Unique(clolumns={"qid","uid"},name="UNI_ANSWER_QID_UID")})
14
@Table
15
public class Answer  implements CreateTimeSupported,ModifyTimeSupported{
16
	private String id;
17
	private String qid;
18
	private String uid;
19
	private String state;
20
	private String cnt;
21
	
22
	private long accept;
23
	private long  ballot;
24
	private String createTime;
25
	private String modifyTime;
26
	/**
27
	 * ID
28
	 * @return
29
	 */
30
	@Column(DE.id_32)
31
	public String getId() {
32
		return id;
33
	}
34
	public void setId(String id) {
35
		this.id = id;
36
	}
37
	/**
38
	 * 问题ID
39
	 * @return
40
	 */
41
	@Column(DE.text_de)
42
	public String getQid() {
43
		return qid;
44
	}
45
	public void setQid(String qid) {
46
		this.qid = qid;
47
	}
48
	/**
49
	 * 回答人ID
50
	 * @return
51
	 */
52
	@Column(DE.text_de)
53
	public String getUid() {
54
		return uid;
55
	}
56
	public void setUid(String uid) {
57
		this.uid = uid;
58
	}
59
	/**
60
	 * 状态 1:发布中   
61
	 * @return
62
	 */
63
	@Column(DE.singleChar)
64
	public String getState() {
65
		return state;
66
	}
67
	public void setState(String state) {
68
		this.state = state;
69
	}
70
	/**
71
	 * 回答内容
72
	 * @return
73
	 */
74
	@Column(DE.text_de)
75
	public String getCnt() {
76
		return cnt;
77
	}
78
	public void setCnt(String cnt) {
79
		this.cnt = cnt;
80
	}
81
	/**
82
	 * 点赞数量
83
	 */
84
	@Column(DE.long_de)
85
	public long getAccept() {
86
		return accept;
87
	}
88
	public void setAccept(long accept) {
89
		this.accept = accept;
90
	}
91
	/**
92
	 * 总数投票数
93
	 * @return
94
	 */
95
	@Column(DE.long_de)
96
	public long getBallot() {
97
		return ballot;
98
	}
99
	public void setBallot(long ballot) {
100
		this.ballot = ballot;
101
	}
102
	public String getCreateTime() {
103
		return createTime;
104
	}
105
	public void setCreateTime(String createTime) {
106
		this.createTime = createTime;
107
	}
108
	public String getModifyTime() {
109
		return modifyTime;
110
	}
111
	public void setModifyTime(String modifyTime) {
112
		this.modifyTime = modifyTime;
113
	}
114
	
115
	
116
	
117
	
118
	
119
}

+ 37 - 0
src/main/java/com/ekexiu/portal/question/AnswerAcceptRec.java

@ -0,0 +1,37 @@
1
package com.ekexiu.portal.question;
2

3
import org.jfw.apt.orm.annotation.entry.Column;
4
import org.jfw.apt.orm.annotation.entry.PrimaryKey;
5
import org.jfw.apt.orm.annotation.entry.Table;
6
import org.jfw.apt.orm.core.enums.DE;
7

8
@PrimaryKey({"uid","aid"})
9
@Table
10
public class AnswerAcceptRec{
11

12
	private String uid;
13
	private String aid;
14
	private boolean flag;
15
	@Column(DE.text_de)
16
	public String getUid() {
17
		return uid;
18
	}
19
	public void setUid(String uid) {
20
		this.uid = uid;
21
	}
22
	@Column(DE.text_de)
23
	public String getAid() {
24
		return aid;
25
	}
26
	public void setAid(String aid) {
27
		this.aid = aid;
28
	}
29
	@Column(DE.boolean_de)
30
	public boolean isFlag() {
31
		return flag;
32
	}
33
	public void setFlag(boolean flag) {
34
		this.flag = flag;
35
	}
36
	
37
}

+ 29 - 0
src/main/java/com/ekexiu/portal/question/QetKeyWord.java

@ -0,0 +1,29 @@
1
package com.ekexiu.portal.question;
2

3
import org.jfw.apt.orm.annotation.entry.Column;
4
import org.jfw.apt.orm.annotation.entry.PrimaryKey;
5
import org.jfw.apt.orm.annotation.entry.Table;
6
import org.jfw.apt.orm.core.enums.DE;
7

8
@PrimaryKey({"id","kw"})
9
@Table
10
public class QetKeyWord {
11
	private String id;
12
	private String kw;
13
	@Column(DE.text_de)
14
	public String getId() {
15
		return id;
16
	}
17
	public void setId(String id) {
18
		this.id = id;
19
	}
20
	@Column(DE.text_de)
21
	public String getKw() {
22
		return kw;
23
	}
24
	public void setKw(String kw) {
25
		this.kw = kw;
26
	}
27
	
28
	
29
}

+ 136 - 0
src/main/java/com/ekexiu/portal/question/Question.java

@ -0,0 +1,136 @@
1
package com.ekexiu.portal.question;
2

3
import org.jfw.apt.orm.annotation.entry.Column;
4
import org.jfw.apt.orm.annotation.entry.PrimaryKey;
5
import org.jfw.apt.orm.annotation.entry.Table;
6
import org.jfw.apt.orm.core.defaultImpl.FixLenStringHandler;
7
import org.jfw.apt.orm.core.enums.DE;
8

9
import com.ekexiu.portal.basepo.CreateTimeSupported;
10
import com.ekexiu.portal.basepo.ModifyTimeSupported;
11

12
@PrimaryKey("id")
13
@Table
14
public class Question implements CreateTimeSupported,ModifyTimeSupported{
15
	
16
	private String id;
17
	private String title;
18
	private String cnt;
19
	private String img;
20
	private String createTime;
21
	private String modifyTime;
22
	private String keys;
23
	private String uid;	
24
	private String lastReplyTime;
25
	private long replyCount;
26
	private String state;
27
	
28
	/**
29
	 * ID
30
	 * @return
31
	 */
32
	@Column(DE.id_32)
33
	public String getId() {
34
		return id;
35
	}
36
	public void setId(String id) {
37
		this.id = id;
38
	}
39
	@Column(DE.text_de)
40
	public String getTitle() {
41
		return title;
42
	}
43
	public void setTitle(String title) {
44
		this.title = title;
45
	}
46
	/**
47
	 * 提问内容
48
	 * @return
49
	 */
50
	@Column(DE.Text_de)
51
	public String getCnt() {
52
		return cnt;
53
	}
54
	public void setCnt(String cnt) {
55
		this.cnt = cnt;
56
	}
57
	/**
58
	 * 图片 用英文豆号分隔
59
	 * @return
60
	 */
61
	@Column(DE.Text_de)
62
	public String getImg() {
63
		return img;
64
	}
65
	public void setImg(String img) {
66
		this.img = img;
67
	}
68
	public String getCreateTime() {
69
		return createTime;
70
	}
71
	public void setCreateTime(String createTime) {
72
		this.createTime = createTime;
73
	}
74
	public String getModifyTime() {
75
		return modifyTime;
76
	}
77
	public void setModifyTime(String modifyTime) {
78
		this.modifyTime = modifyTime;
79
	}
80
	/**
81
	 * 关键词,以英文逗号分隔
82
	 * @return
83
	 */
84
	@Column(DE.text_de)
85
	public String getKeys() {
86
		return keys;
87
	}
88
	public void setKeys(String keys) {
89
		this.keys = keys;
90
	}
91
	/**
92
	 * 发布人ID
93
	 * @return
94
	 */
95
	@Column(DE.text_de)
96
	public String getUid() {
97
		return uid;
98
	}
99
	public void setUid(String uid) {
100
		this.uid = uid;
101
	}
102
	/**
103
	 * 最后回答时间
104
	 * @return
105
	 */
106
	@Column(handlerClass = FixLenStringHandler.class, dbType = "CHAR(14)", fixSqlValueWithUpdate = "TO_CHAR(NOW(),'YYYYMMDDHH24MISS')", insertable = false, nullable = true, queryable = true, renewable = true)
107
	public String getLastReplyTime() {
108
		return lastReplyTime;
109
	}
110
	public void setLastReplyTime(String lastReplyTime) {
111
		this.lastReplyTime = lastReplyTime;
112
	}
113
	/**
114
	 * 回答次数
115
	 * @return
116
	 */
117
	@Column(DE.long_de)
118
	public long getReplyCount() {
119
		return replyCount;
120
	}
121
	public void setReplyCount(long replyCount) {
122
		this.replyCount = replyCount;
123
	}
124
	/**
125
	 * 提问状态  1:发布中
126
	 * @return
127
	 */
128
	@Column(DE.singleChar)
129
	public String getState() {
130
		return state;
131
	}
132
	public void setState(String state) {
133
		this.state = state;
134
	}
135
	
136
}

+ 108 - 0
src/main/java/com/ekexiu/portal/question/QuestionDao.java

@ -0,0 +1,108 @@
1
package com.ekexiu.portal.question;
2

3
import java.sql.Connection;
4
import java.sql.SQLException;
5
import java.util.List;
6

7
import org.jfw.apt.annotation.Nullable;
8
import org.jfw.apt.orm.annotation.dao.Batch;
9
import org.jfw.apt.orm.annotation.dao.DAO;
10
import org.jfw.apt.orm.annotation.dao.method.From;
11
import org.jfw.apt.orm.annotation.dao.method.IncludeFixSet;
12
import org.jfw.apt.orm.annotation.dao.method.OrderBy;
13
import org.jfw.apt.orm.annotation.dao.method.SetSentence;
14
import org.jfw.apt.orm.annotation.dao.method.Where;
15
import org.jfw.apt.orm.annotation.dao.method.operator.DeleteWith;
16
import org.jfw.apt.orm.annotation.dao.method.operator.Insert;
17
import org.jfw.apt.orm.annotation.dao.method.operator.LimitQuery;
18
import org.jfw.apt.orm.annotation.dao.method.operator.LimitSelect;
19
import org.jfw.apt.orm.annotation.dao.method.operator.SelectList;
20
import org.jfw.apt.orm.annotation.dao.method.operator.SelectOne;
21
import org.jfw.apt.orm.annotation.dao.method.operator.UpdateWith;
22
import org.jfw.apt.orm.annotation.dao.param.GreaterThan;
23
import org.jfw.apt.orm.annotation.dao.param.In;
24
import org.jfw.apt.orm.annotation.dao.param.LtEq;
25
import org.jfw.apt.orm.annotation.dao.param.Set;
26
import org.jfw.apt.orm.annotation.dao.param.SqlColumn;
27
import org.jfw.apt.orm.core.defaultImpl.IntHandler;
28
import org.jfw.apt.orm.core.defaultImpl.StringHandler;
29

30
@DAO
31
public interface QuestionDao {
32

33
	@Insert
34
	int insert(Connection con, Question qen) throws SQLException;
35

36
	@DeleteWith
37
	@From(QetKeyWord.class)
38
	int deleteKeys(Connection con, String id) throws SQLException;
39

40
	@Insert
41
	@Batch
42
	int[] insert(Connection con, QetKeyWord[] kws) throws SQLException;
43

44
	@LimitSelect
45
	@OrderBy("ORDER BY CREATE_TIME DESC,ID ASC")
46
	List<Question> query(Connection con, @Nullable String state, String uid, @LtEq String createTime, @GreaterThan String id, int rows) throws SQLException;
47

48
	@LimitSelect
49
	@OrderBy("ORDER BY CREATE_TIME DESC,ID ASC")
50
	@Where(" STATE='1'")
51
	List<Question> watch(Connection con,
52
			@SqlColumn(handlerClass = StringHandler.class, value = {
53
					" ID IN (SELECT WATCH_OBJECT FROM WATCH WHERE WATCH_TYPE='8' AND PROFESSOR_ID=?)" }) String uid,
54
			@LtEq String createTime, @GreaterThan String id, int rows) throws SQLException;
55

56
	@SelectOne
57
	@Nullable
58
	Question query(Connection con, String id) throws SQLException;
59

60
	@SelectList
61
	List<Question> query(Connection con, @In String[] id) throws SQLException;
62

63
	@LimitSelect
64
	@OrderBy("ORDER BY CREATE_TIME DESC,ID ASC")
65
	@Where("QID IN(SELECT ID FROM QUESTION WHERE STATE='1') AND STATE='1'")
66
	List<Answer> answerSelf(Connection con, String uid, @LtEq String createTime, @GreaterThan String id, int rows) throws SQLException;
67

68
	@LimitSelect
69
	@OrderBy("ORDER BY CREATE_TIME DESC,ID ASC")
70
	@Where("QID IN(SELECT ID FROM QUESTION WHERE STATE='1') AND STATE='1'")
71
	List<Answer> watchAnswer(Connection con,
72
			@SqlColumn(handlerClass = StringHandler.class, value = {
73
					" ID IN (SELECT WATCH_OBJECT FROM WATCH WHERE WATCH_TYPE='9' AND PROFESSOR_ID=?)" }) String uid,
74
			@LtEq String createTime, @GreaterThan String id, int rows) throws SQLException;
75

76
	@LimitSelect
77
	@OrderBy("ORDER BY CREATE_TIME DESC,ID ASC")
78
	List<Answer> byQes(Connection con, String qid, @LtEq String createTime, @GreaterThan String id, int rows) throws SQLException;
79
	@LimitQuery
80
	@OrderBy("ORDER BY SCORE DESC,ID ASC")
81
	List<SortedAnswwer> byQes(Connection con, String qid, @SqlColumn(handlerClass = IntHandler.class, value = { "10000 * ACCEPT / BALLOT <= ?  " }) int score, @GreaterThan String id, int rows) throws SQLException;
82

83
	@Insert
84
	int insert(Connection con,AnswerAcceptRec aar)throws SQLException;
85
	@UpdateWith
86
	@From(AnswerAcceptRec.class)
87
	@Where("FLAG<>'1'")
88
	@SetSentence("FLAG='1'")
89
	int accept(Connection con,String uid,String aid)throws SQLException;
90
	@UpdateWith
91
	@From(AnswerAcceptRec.class)
92
	@Where("FLAG='1'")
93
	@SetSentence("FLAG='0'")
94
	int unAccept(Connection con,String uid,String aid)throws SQLException;
95
	
96
	@UpdateWith
97
	@From(Answer.class)
98
	int update(Connection con,String id, @Set( " = ACCEPT +?" ) long accept,@Set("=BALLOT+?") long ballot)throws SQLException;
99
	
100
	
101
	@Insert
102
	int insert(Connection con, Answer answer) throws SQLException;
103

104
	@UpdateWith
105
	@From(Answer.class)
106
	@IncludeFixSet
107
	int updateAnswer(Connection con, String id, @Set String cnt) throws SQLException;
108
}

+ 617 - 0
src/main/java/com/ekexiu/portal/question/Service.java

@ -0,0 +1,617 @@
1
package com.ekexiu.portal.question;
2

3
import java.io.File;
4
import java.io.FileOutputStream;
5
import java.io.InputStream;
6
import java.io.OutputStream;
7
import java.sql.Connection;
8
import java.sql.PreparedStatement;
9
import java.sql.SQLException;
10
import java.util.ArrayList;
11
import java.util.LinkedList;
12
import java.util.List;
13
import java.util.Map;
14
import java.util.concurrent.atomic.AtomicInteger;
15

16
import org.jfw.apt.annotation.Autowrie;
17
import org.jfw.apt.annotation.DefaultValue;
18
import org.jfw.apt.web.annotation.Path;
19
import org.jfw.apt.web.annotation.operate.Get;
20
import org.jfw.apt.web.annotation.operate.Post;
21
import org.jfw.apt.web.annotation.param.AfterCommit;
22
import org.jfw.apt.web.annotation.param.FieldParam;
23
import org.jfw.apt.web.annotation.param.JdbcConn;
24
import org.jfw.apt.web.annotation.param.RequestParam;
25
import org.jfw.apt.web.annotation.param.Upload;
26
import org.jfw.util.ListUtil;
27
import org.jfw.util.StringUtil;
28
import org.jfw.util.exception.JfwBaseException;
29
import org.jfw.util.jdbc.JdbcUtil;
30
import org.jfw.util.jdbc.PreparedStatementConfig;
31
import org.jfw.util.web.fileupload.Item;
32
import org.jfw.util.web.fileupload.UploadItemIterator;
33

34
import com.ekexiu.portal.util.SqlUtil;
35

36
@Path("/question")
37
public class Service {
38

39
	private static final AtomicInteger FN_IDX = new AtomicInteger(1);
40

41
	@Autowrie
42
	private QuestionDao questionDao;
43

44
	private File imgPath;
45

46
	public File getImgPath() {
47
		return imgPath;
48
	}
49

50
	public void setImgPath(File imgPath) {
51
		this.imgPath = imgPath;
52
	}
53

54
	public QuestionDao getQuestionDao() {
55
		return questionDao;
56
	}
57

58
	public void setQuestionDao(QuestionDao questionDao) {
59
		this.questionDao = questionDao;
60
	}
61

62
	/**
63
	 * 上传文件
64
	 * 
65
	 * @param it
66
	 * @return
67
	 * @throws Exception
68
	 */
69
	@Path("/upload")
70
	@Post
71
	public List<UploadFile> upload(@Upload UploadItemIterator it) throws Exception {
72
		List<UploadFile> ret = new LinkedList<UploadFile>();
73
		try {
74
			while (it.hasNext()) {
75
				Item item = it.next();
76
				if (!item.isFormField()) {
77
					String name = normalizeFileName(item.getName());
78
					int index = name.lastIndexOf('.');
79
					String ext = index >= 0 ? name.substring(index + 1) : "";
80
					ext = ext.trim();
81
					long fileLen = 0;
82
					int len = 0;
83
					UploadFile uf = this.buildTargetFile(ext);
84
					uf.setName(name);
85
					File file = uf.getFn();
86
					ret.add(uf);
87
					byte[] buf = new byte[8092];
88
					OutputStream of = new FileOutputStream(file);
89
					try {
90
						InputStream in = item.getInputStream();
91
						try {
92
							while ((len = in.read(buf)) >= 0) {
93
								if (len > 0) {
94
									of.write(buf, 0, len);
95
									fileLen += len;
96
								}
97
							}
98
							uf.setSize(fileLen);
99
						} finally {
100
							in.close();
101
						}
102
					} finally {
103
						of.close();
104
					}
105
				}
106
			}
107
			return ret;
108
		} catch (Exception e) {
109
			this.remove(ret);
110
			throw e;
111
		} finally {
112
			if (it != null)
113
				it.clean();
114
		}
115
	}
116

117
	/**
118
	 * 新增一提问
119
	 * 
120
	 * @param con
121
	 * @param q
122
	 *            title 标题 ,cnt 描述 img 图片 以英文逗号分隔, keys 关键字 以英文逗号分隔 ,uid 用户ID
123
	 * @return
124
	 * @throws SQLException
125
	 */
126
	@Path()
127
	@Post
128
	public String save(@JdbcConn(true) Connection con,
129
			@RequestParam(fields = { @FieldParam(value = "title", valueClass = String.class),
130
					@FieldParam(value = "cnt", valueClass = String.class, required = false),
131
					@FieldParam(value = "img", valueClass = String.class, required = false), @FieldParam(value = "keys", valueClass = String.class),
132
					@FieldParam(value = "uid", valueClass = String.class) }) Question q)
133
			throws SQLException {
134
		String id = StringUtil.buildUUID();
135
		q.setId(id);
136
		q.setReplyCount(0);
137
		q.setState("1");
138
		List<String> kws = ListUtil.splitTrimExcludeEmpty(q.getKeys(), ',');
139
		if (kws.isEmpty())
140
			throw new IllegalArgumentException("param keys invalid");
141
		questionDao.insert(con, q);
142
		questionDao.insert(con, build(id, kws));
143
		return id;
144
	}
145

146
	/**
147
	 * 默认的邀请专家
148
	 * 
149
	 * @param con
150
	 * @param id
151
	 *            提问ID
152
	 * @param count
153
	 *            limit 查询 返回最后一条的 kws ,首次不传
154
	 * @param pid
155
	 *            limit 查询 返回最后一条的 id 首次可不传
156
	 * @param rows
157
	 *            limit查询返回的最大数据条数
158
	 * @return
159
	 * @throws SQLException
160
	 */
161
	@Get
162
	@Path("/commendatoryPro")
163
	public List<Map<String, Object>> professor(@JdbcConn Connection con, final String id, final @DefaultValue("Integer.MAX_VALUE") int count,
164
			final @DefaultValue("\"0\"") String pid, final @DefaultValue("Integer.MAX_VALUE") int rows) throws SQLException {
165
		return JdbcUtil.queryMaps(con,
166
				"select id, kws from(select id,count(1) kws from pro_key_word where kw in (select kw from pro_key_word where id =?) group by id ) t where kws<= ? and id >? order by kws desc,id asc limit ?",
167
				new PreparedStatementConfig() {
168
					@Override
169
					public void config(PreparedStatement ps) throws SQLException {
170
						ps.setString(1, id);
171
						ps.setInt(2, count);
172
						ps.setString(3, pid);
173
						ps.setInt(4, rows);
174
					}
175
				});
176
	}
177

178
	/**
179
	 * 邀请专家回答提问
180
	 * 
181
	 * @param con
182
	 * @param id
183
	 *            提问id
184
	 * @param pid
185
	 *            专家id(被邀请人)
186
	 * @param uid
187
	 *            操作人(邀请人
188
	 * @param uname
189
	 *            操作人(邀请人)姓名
190
	 * @return
191
	 * @throws SQLException
192
	 * @throws JfwBaseException
193
	 */
194
	@Post
195
	@Path("/invite")
196
	public boolean invite(@JdbcConn Connection con, String id, String pid, String uid, String uname) throws SQLException, JfwBaseException {
197
		Question q = questionDao.query(con, id);
198
		if (q == null) {
199
			throw new JfwBaseException(50000, "question[" + id + "] not found");
200
		}
201
		// TODO: send notify
202
		return true;
203
	}
204

205
	/**
206
	 * 回答一个提问
207
	 * 
208
	 * @param con
209
	 * @param qid
210
	 *            提问ID
211
	 * @param cnt
212
	 *            回答内容
213
	 * @param uid
214
	 *            回答 人ID
215
	 * @param uname
216
	 *            回答人姓名
217
	 * @return
218
	 * @throws SQLException
219
	 * @throws JfwBaseException
220
	 */
221
	@Post
222
	@Path("/answer")
223
	public String answer(@JdbcConn(true) Connection con, String qid, String cnt, String uid, String uname) throws SQLException, JfwBaseException {
224
		Question q = questionDao.query(con, qid);
225
		if (q == null) {
226
			throw new JfwBaseException(50000, "question[" + qid + "] not found");
227
		}
228
		String id = StringUtil.buildUUID();
229
		Answer a = new Answer();
230
		a.setId(id);
231
		a.setAccept(0);
232
		a.setBallot(0);
233
		a.setCnt(cnt);
234
		a.setQid(qid);
235
		a.setState("1");
236
		a.setUid(uid);
237
		try {
238
			questionDao.insert(con, a);
239
		} catch (SQLException e) {
240
			if (SqlUtil.unique(e)) {
241
				throw new JfwBaseException(50001, "duplicate answer");
242
			}
243
			throw e;
244
		}
245
		return id;
246
	}
247

248
	/**
249
	 * 修改一个回答
250
	 * 
251
	 * @param con
252
	 * @param id
253
	 *            回答ID
254
	 * @param cnt
255
	 *            回答内容
256
	 * @param uid
257
	 *            用户ID
258
	 * @param uname
259
	 *            用户姓名
260
	 * @return
261
	 * @throws SQLException
262
	 */
263
	@Post
264
	@Path("/answer/modify")
265
	public int answerUpdate(@JdbcConn(true) Connection con, String id, String cnt, String uid, String uname) throws SQLException {
266
		return questionDao.updateAnswer(con, id, cnt);
267
	}
268

269
	@Get
270
	@Path("/qo")
271
	public Question queryOne(@JdbcConn Connection con, String id) throws SQLException {
272
		return questionDao.query(con, id);
273
	}
274

275
	@Get
276
	@Path("/qm")
277
	public List<Question> queryOne(@JdbcConn Connection con, String[] ids) throws SQLException {
278
		return questionDao.query(con, ids);
279
	}
280

281
	/**
282
	 * 等您回答 1、只显示“发布中”的问题 按问题发布时间,由新到旧排序。
283
	 * 
284
	 * @param con
285
	 * @param time
286
	 *            limit查询最后一条的createTime 首次不传
287
	 * @param id
288
	 *            limit查询最后一条的id 首次不传
289
	 * @param rows
290
	 *            limit查询最后一条的最大返回条数
291
	 * @return
292
	 * @throws SQLException
293
	 */
294
	@Get
295
	@Path()
296
	public List<Question> query(@JdbcConn Connection con, @DefaultValue("\"0\"") String time, @DefaultValue("\"0\"") String id,
297
			@DefaultValue("10000000") int rows) throws SQLException {
298
		return questionDao.query(con, "1", null, time, id, rows);
299
	}
300

301
	/**
302
	 * 我提出的 1、只显示“发布中”的问题 按问题发布时间,由新到旧排序。
303
	 * 
304
	 * @param con
305
	 * @param uid
306
	 *            用户ID
307
	 * @param time
308
	 *            limit查询最后一条的createTime 首次不传
309
	 * @param id
310
	 *            limit查询最后一条的id 首次不传
311
	 * @param rows
312
	 *            limit查询最后一条的最大返回条数
313
	 * @return
314
	 * @throws SQLException
315
	 */
316
	@Get
317
	@Path("/my")
318
	public List<Question> querySelf(@JdbcConn Connection con, String uid, @DefaultValue("\"0\"") String time, @DefaultValue("\"0\"") String id,
319
			@DefaultValue("10000000") int rows) throws SQLException {
320
		return questionDao.query(con, "1", uid, time, id, rows);
321
	}
322

323
	/**
324
	 * 我关注的 1、只显示“发布中”的问题 按问题发布时间,由新到旧排序。
325
	 * 
326
	 * @param con
327
	 * @param uid
328
	 *            用户ID
329
	 * @param time
330
	 *            limit查询最后一条的createTime 首次不传
331
	 * @param id
332
	 *            limit查询最后一条的id 首次不传
333
	 * @param rows
334
	 *            limit查询最后一条的最大返回条数
335
	 * @return
336
	 * @throws SQLException
337
	 */
338
	@Get
339
	@Path("/watch")
340
	public List<Question> watch(@JdbcConn Connection con, String uid, @DefaultValue("\"0\"") String time, @DefaultValue("\"0\"") String id,
341
			@DefaultValue("10000000") int rows) throws SQLException {
342
		return questionDao.watch(con, uid, time, id, rows);
343
	}
344

345
	/**
346
	 * 我回答的
347
	 * 
348
	 * @param con
349
	 * @param uid
350
	 *            用户ID
351
	 * @param time
352
	 *            limit查询最后一条的createTime 首次不传
353
	 * @param id
354
	 *            limit查询最后一条的id 首次不传
355
	 * @param rows
356
	 *            limit查询最后一条的最大返回条数
357
	 * @return
358
	 * @throws SQLException
359
	 */
360
	@Get
361
	@Path("/answer/my")
362
	public List<Answer> answerSelf(@JdbcConn Connection con, String uid, @DefaultValue("\"0\"") String time, @DefaultValue("\"0\"") String id,
363
			@DefaultValue("10000000") int rows) throws SQLException {
364
		return questionDao.answerSelf(con, uid, time, id, rows);
365
	}
366

367
	/**
368
	 * 我关注的回答
369
	 * 
370
	 * @param con
371
	 * @param uid
372
	 *            用户ID
373
	 * @param time
374
	 *            limit查询最后一条的createTime 首次不传
375
	 * @param id
376
	 *            limit查询最后一条的id 首次不传
377
	 * @param rows
378
	 *            limit查询最后一条的最大返回条数
379
	 * @return
380
	 * @throws SQLException
381
	 */
382
	@Get
383
	@Path("/answer/my")
384
	public List<Answer> answerWatch(@JdbcConn Connection con, String uid, @DefaultValue("\"0\"") String time, @DefaultValue("\"0\"") String id,
385
			@DefaultValue("10000000") int rows) throws SQLException {
386
		return questionDao.watchAnswer(con, uid, time, id, rows);
387
	}
388
	/**
389
	 * 指定提问的回答(按最新回答时间,由新到旧排序)
390
	 * 
391
	 * @param con
392
	 * @param qid
393
	 *            提问ID
394
	 * @param time
395
	 *            limit查询最后一条的createTime 首次不传
396
	 * @param id
397
	 *            limit查询最后一条的id 首次不传
398
	 * @param rows
399
	 *            limit查询最后一条的最大返回条数
400
	 * @return
401
	 * @throws SQLException
402
	 */
403
	@Get
404
	@Path("/answer/qes/byTime")
405
	public List<Answer> byQes(@JdbcConn Connection con, String qid, @DefaultValue("\"0\"") String time, @DefaultValue("\"0\"") String id,
406
			@DefaultValue("10000000") int rows) throws SQLException {
407
		return questionDao.byQes(con, qid, time, id, rows);
408
	}
409
	/**
410
	 * 指定提问的回答(按最新回答时间,由新到旧排序)
411
	 * 
412
	 * @param con
413
	 * @param qid
414
	 *            提问ID
415
	 * @param score
416
	 *            limit查询最后一条的score 首次不传
417
	 * @param id
418
	 *            limit查询最后一条的id 首次不传
419
	 * @param rows
420
	 *            limit查询最后一条的最大返回条数
421
	 * @return
422
	 * @throws SQLException
423
	 */
424
	@Get
425
	@Path("/answer/qes/byScore")
426
	public List<SortedAnswwer> byQes(@JdbcConn Connection con, String qid, @DefaultValue("100000") int score, @DefaultValue("\"0\"") String id,
427
			@DefaultValue("10000000") int rows) throws SQLException {
428
		return questionDao.byQes(con, qid, score, id, rows);
429
	}
430

431
	/**
432
	 * 我的回答总点赞数
433
	 * 
434
	 * @param con
435
	 * @param id
436
	 *            用户ID
437
	 * @return
438
	 * @throws SQLException
439
	 */
440
	@Get
441
	@Path("/answer/my/accept/count")
442
	public int queryCountWithMyAnswer(@JdbcConn Connection con, final String id) throws SQLException {
443
		return JdbcUtil.queryInt(con, "SELECT COUNT(ACCEPT) FROM ANSWER WHERE UID=?", new PreparedStatementConfig() {
444
			@Override
445
			public void config(PreparedStatement ps) throws SQLException {
446
				ps.setString(1, id);
447
			}
448
		}, 0);
449
	}
450
	
451
	@Post
452
	@Path("/answer/accept")
453
	public void accept(@JdbcConn(true) Connection con,String id,String uid,String uname,@AfterCommit List<Runnable> runs)throws SQLException, JfwBaseException{
454
		AnswerAcceptRec aar = new AnswerAcceptRec();
455
		aar.setAid(id);
456
		aar.setUid(uid);
457
		aar.setFlag(true);
458
		boolean inserted = false;
459
		try{
460
			questionDao.insert(con,aar);
461
			inserted=true;
462
		}catch(SQLException e){
463
			if(SqlUtil.unique(e)){
464
				con.rollback();
465
			}
466
			throw e;
467
		}
468
		if(inserted){
469
			questionDao.update(con, id, 1, 1);
470
		}else{
471
			if(questionDao.accept(con, uid, id) >0){
472
				questionDao.update(con,id,1,0);
473
			}else{
474
				throw new JfwBaseException(50001,"duplicate answer accept");
475
			}
476
			
477
		}
478
		runs.add(new Runnable(){
479

480
			@Override
481
			public void run() {
482
				// TODO send notify
483
			}});
484
	}
485
	@Post
486
	@Path("/answer/unAccept")
487
	public void unAccept(@JdbcConn(true) Connection con,String id,String uid,String uname,@AfterCommit List<Runnable> runs)throws SQLException, JfwBaseException{
488
		AnswerAcceptRec aar = new AnswerAcceptRec();
489
		aar.setAid(id);
490
		aar.setUid(uid);
491
		aar.setFlag(false);
492
		boolean inserted = false;
493
		try{
494
			questionDao.insert(con,aar);
495
			inserted=true;
496
		}catch(SQLException e){
497
			if(SqlUtil.unique(e)){
498
				con.rollback();
499
			}
500
			throw e;
501
		}
502
		if(inserted){
503
			questionDao.update(con, id, 0, 1);
504
		}else{
505
			if(questionDao.unAccept(con, uid, id) >0){
506
				questionDao.update(con,id,-1,0);
507
			}else{
508
				throw new JfwBaseException(50001,"duplicate answer unaccept");
509
			}
510
		}
511
		runs.add(new Runnable(){
512

513
			@Override
514
			public void run() {
515
				// TODO send notify
516
			}});
517
	}
518

519
	public QetKeyWord[] build(String id, List<String> ss) {
520
		List<QetKeyWord> qKws = new ArrayList<>(ss.size());
521
		for (String s : ss) {
522
			QetKeyWord kw = new QetKeyWord();
523
			kw.setId(id);
524
			kw.setKw(s);
525
			qKws.add(kw);
526
		}
527
		return qKws.toArray(new QetKeyWord[qKws.size()]);
528
	}
529

530
	private void remove(List<UploadFile> list) {
531
		for (UploadFile file : list) {
532
			if (file.fn != null)
533
				file.fn.delete();
534
		}
535
	}
536

537
	private UploadFile buildTargetFile(String ext) {
538
		StringBuilder sb = new StringBuilder();
539
		sb.append(System.currentTimeMillis() / (1000 * 60 * 60 * 24));
540
		File path = new File(this.imgPath, sb.toString());
541
		if (!path.exists()) {
542
			synchronized (this) {
543
				if (!path.mkdirs())
544
					throw new RuntimeException("mkdir error[" + path + "]");
545
				FN_IDX.set(1);
546
			}
547
		}
548
		File file;
549
		do {
550
			String fn = FN_IDX.toString();
551
			if (ext.isEmpty()) {
552
				file = new File(path, fn);
553
			} else {
554
				file = new File(path, fn + "." + ext);
555
			}
556
			FN_IDX.incrementAndGet();
557
		} while (file.exists());
558
		sb.append("/").append(file.getName());
559
		UploadFile uf = new UploadFile();
560
		uf.setFn(file);
561
		uf.setUri("/" + sb.toString());
562
		return uf;
563
	}
564

565
	private String normalizeFileName(String fn) {
566
		int index = fn.indexOf('\\');
567
		if (index >= 0) {
568
			fn = fn.substring(fn.lastIndexOf('\\') + 1);
569
		}
570
		index = fn.indexOf('/');
571
		if (index >= 0) {
572
			fn = fn.substring(fn.lastIndexOf('/') + 1);
573
		}
574
		if (fn.length() == 0)
575
			throw new RuntimeException("invalid filename in Multipart/data request");
576
		return fn;
577
	}
578

579
	public static class UploadFile {
580
		private String name;
581
		private String uri;
582
		private long size;
583
		private transient File fn;
584

585
		public File getFn() {
586
			return fn;
587
		}
588

589
		public void setFn(File fn) {
590
			this.fn = fn;
591
		}
592

593
		public String getName() {
594
			return name;
595
		}
596

597
		public void setName(String name) {
598
			this.name = name;
599
		}
600

601
		public String getUri() {
602
			return uri;
603
		}
604

605
		public void setUri(String uri) {
606
			this.uri = uri;
607
		}
608

609
		public long getSize() {
610
			return size;
611
		}
612

613
		public void setSize(long size) {
614
			this.size = size;
615
		}
616
	}
617
}

+ 20 - 0
src/main/java/com/ekexiu/portal/question/SortedAnswwer.java

@ -0,0 +1,20 @@
1
package com.ekexiu.portal.question;
2

3
import org.jfw.apt.orm.annotation.entry.CalcColumn;
4
import org.jfw.apt.orm.annotation.entry.ExtendTable;
5
import org.jfw.apt.orm.core.defaultImpl.LongHandler;
6

7
@ExtendTable
8
public class SortedAnswwer extends Answer {
9
	private long score ;
10

11
	@CalcColumn(nullable=false,handlerClass=LongHandler.class,column="10000 * accept / ballot SCORE")
12
	public long getScore() {
13
		return score;
14
	}
15

16
	public void setScore(long score) {
17
		this.score = score;
18
	}
19
   
20
}

+ 8 - 0
src/main/java/com/ekexiu/portal/util/DebugService.java

@ -1,10 +1,15 @@
1 1
package com.ekexiu.portal.util;
2 2

3
import java.sql.Connection;
4
import java.util.List;
5

3 6
import org.jfw.apt.annotation.Autowrie;
4 7
import org.jfw.apt.annotation.Nullable;
5 8
import org.jfw.apt.web.annotation.Path;
6 9
import org.jfw.apt.web.annotation.operate.Get;
7 10
import org.jfw.apt.web.annotation.operate.Post;
11
import org.jfw.apt.web.annotation.param.AfterCommit;
12
import org.jfw.apt.web.annotation.param.JdbcConn;
8 13

9 14
import com.ekexiu.push.service.PushService;
10 15

@ -41,4 +46,7 @@ public class DebugService {
41 46
		}
42 47
		
43 48
	}
49
	@Get
50
	@Path("/ssssssssssssss")
51
	public void send(@JdbcConn(true) Connection con,@AfterCommit List<Runnable> runs){}
44 52
}

+ 13 - 0
src/main/java/com/ekexiu/portal/util/SqlUtil.java

@ -0,0 +1,13 @@
1
package com.ekexiu.portal.util;
2

3
import java.sql.SQLException;
4

5
public final class SqlUtil {
6
	private SqlUtil() {
7
	}
8

9
	public static boolean unique(SQLException e) {
10
		return "23505".equals(e.getSQLState());
11
	}
12

13
}

+ 2 - 1
src/main/resources/project-test-dev.properties

@ -279,4 +279,5 @@ com_ekexiu_portal_cms_TemplateService.dir::java.io.File=/kexiu/webdata1/shtml
279 279
com_ekexiu_portal_oauth_BaseOAuthHandler=com.ekexiu.portal.oauth.BaseOAuthHandler
280 280
com_ekexiu_portal_oauth_BaseOAuthHandler.type=weixinxiaochengxu
281 281
oauthService_handlers.map-key-2=weixinxiaochengxu
282
oauthService_handlers.map-val-2-ref=com_ekexiu_portal_oauth_BaseOAuthHandler
282
oauthService_handlers.map-val-2-ref=com_ekexiu_portal_oauth_BaseOAuthHandler
283
com_ekexiu_portal_question_Service.imgPath::java.io.File=/kexiu/webdata1/data/question

+ 2 - 1
src/main/resources/project-test.properties

@ -279,4 +279,5 @@ com_ekexiu_portal_cms_TemplateService.dir::java.io.File=/kexiu/webdata/shtml
279 279
com_ekexiu_portal_oauth_BaseOAuthHandler=com.ekexiu.portal.oauth.BaseOAuthHandler
280 280
com_ekexiu_portal_oauth_BaseOAuthHandler.type=weixinxiaochengxu
281 281
oauthService_handlers.map-key-2=weixinxiaochengxu
282
oauthService_handlers.map-val-2-ref=com_ekexiu_portal_oauth_BaseOAuthHandler
282
oauthService_handlers.map-val-2-ref=com_ekexiu_portal_oauth_BaseOAuthHandler
283
com_ekexiu_portal_question_Service.imgPath::java.io.File=/kexiu/webdata/data/question

+ 1 - 1
src/main/resources/project.properties

@ -281,4 +281,4 @@ com_ekexiu_portal_oauth_BaseOAuthHandler=com.ekexiu.portal.oauth.BaseOAuthHandle
281 281
com_ekexiu_portal_oauth_BaseOAuthHandler.type=weixinxiaochengxu
282 282
oauthService_handlers.map-key-2=weixinxiaochengxu
283 283
oauthService_handlers.map-val-2-ref=com_ekexiu_portal_oauth_BaseOAuthHandler
284
284
com_ekexiu_portal_question_Service.imgPath::java.io.File=/kexiu/webdata/data/question;