UserProfileModule.java 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. package xyz.luxnk.lproject.module;
  2. import org.nutz.dao.Chain;
  3. import org.nutz.dao.Cnd;
  4. import org.nutz.dao.DaoException;
  5. import org.nutz.dao.FieldFilter;
  6. import org.nutz.dao.util.Daos;
  7. import org.nutz.img.Images;
  8. import org.nutz.ioc.loader.annotation.IocBean;
  9. import org.nutz.lang.Strings;
  10. import org.nutz.lang.util.NutMap;
  11. import org.nutz.log.Log;
  12. import org.nutz.log.Logs;
  13. import org.nutz.mvc.Mvcs;
  14. import org.nutz.mvc.Scope;
  15. import org.nutz.mvc.adaptor.JsonAdaptor;
  16. import org.nutz.mvc.annotation.*;
  17. import org.nutz.mvc.filter.CheckSession;
  18. import org.nutz.mvc.impl.AdaptorErrorContext;
  19. import org.nutz.mvc.upload.TempFile;
  20. import org.nutz.mvc.upload.UploadAdaptor;
  21. import xyz.luxnk.lproject.bean.UserProfile;
  22. import xyz.luxnk.lproject.util.Toolkit;
  23. import javax.servlet.http.HttpServletRequest;
  24. import javax.servlet.http.HttpSession;
  25. import java.awt.*;
  26. import java.awt.image.BufferedImage;
  27. import java.io.ByteArrayOutputStream;
  28. import java.io.File;
  29. import java.sql.SQLException;
  30. import java.util.Date;
  31. @IocBean
  32. @At("/user/profile")
  33. @Filters(@By(type = CheckSession.class, args = {"me", "/"})) // 检查当前Session是否带me这个属性
  34. public class UserProfileModule extends BaseModule {
  35. public static final Log log = Logs.get();
  36. @At("/")
  37. @GET
  38. @Ok("jsp:jsp.user.profile")
  39. public UserProfile index(@Attr(scope = Scope.SESSION, value = "me")String userId) {
  40. return get(userId);
  41. }
  42. /**
  43. * 获取用户详细信息
  44. * @param userId
  45. * @return
  46. */
  47. @At
  48. public UserProfile get(@Attr(scope = Scope.SESSION, value = "me")String userId) {
  49. UserProfile profile = Daos.ext(dao, FieldFilter.locked(UserProfile.class, "avatar")).fetch(UserProfile.class, userId);
  50. if (profile == null) {
  51. profile = new UserProfile();
  52. profile.setUserId(userId);
  53. profile.setCreateTime(new Date());
  54. profile.setUpdateTime(new Date());
  55. dao.insert(profile);
  56. }
  57. return profile;
  58. }
  59. /**
  60. * 更新用户详细信息
  61. * @param profile
  62. * @param userId
  63. */
  64. @At
  65. @AdaptBy(type = JsonAdaptor.class)
  66. @Ok("void")
  67. public void update(@Param("..")UserProfile profile, @Attr(scope = Scope.SESSION, value = "me")String userId) {
  68. if (profile == null)
  69. return;
  70. profile.setUserId(userId); // 修正userId,防止恶意修改其他用户信息
  71. profile.setUpdateTime(new Date());
  72. profile.setAvatar(null); // 不准通过这个方法更新
  73. UserProfile old = get(userId);
  74. // 检查email相关的更新
  75. if (old.getEmail() == null) {
  76. // 老的邮箱为null,所以新邮箱的肯定为未检查状态
  77. profile.setEmailChecked(false);
  78. } else {
  79. if (profile.getEmail() == null) {
  80. profile.setEmail(old.getEmail());
  81. profile.setEmailChecked(old.isEmailChecked());
  82. } else if (! profile.getEmail().equals(old.getEmail())) {
  83. // 设置新邮箱的场合,邮箱状态设置为未检查状态
  84. profile.setEmailChecked(false);
  85. } else {
  86. profile.setEmailChecked(old.isEmailChecked());
  87. }
  88. }
  89. Daos.ext(dao, FieldFilter.create(UserProfile.class, null, "avatar", true)).update(profile);
  90. }
  91. /**
  92. * 上传用户头像
  93. * @param tf
  94. * @param userId
  95. * @param err
  96. */
  97. @AdaptBy(type = UploadAdaptor.class, args = {"${app.root}/WEB-INF/tmp/user_avatar", "8192", "utf-8", "20000", "1024000"})
  98. @POST
  99. @Ok(">>:/user/profile")
  100. @At("/avatar")
  101. public void uploadAvatar(@Param("file")TempFile tf, @Attr(scope = Scope.SESSION, value = "me")String userId, AdaptorErrorContext err) {
  102. String msg = null;
  103. if (err != null && err.getAdaptorErr() != null) {
  104. msg = "文件大小不符合规定";
  105. } else if (tf == null) {
  106. msg = "空文件";
  107. } else {
  108. UserProfile profile = get(userId);
  109. try {
  110. BufferedImage image = Images.read(tf.getFile());
  111. image = Images.zoomScale(image, 128, 128, Color.WHITE);
  112. ByteArrayOutputStream out = new ByteArrayOutputStream();
  113. Images.writeJpeg(image, out, 0.8f);
  114. profile.setAvatar(out.toByteArray());
  115. dao.update(profile, "^avatar$");
  116. } catch (DaoException e) {
  117. log.info("System Error", e);
  118. msg = "系统错误";
  119. } catch (Throwable e) {
  120. msg = "图片格式错误";
  121. }
  122. }
  123. if (msg != null) {
  124. Mvcs.getHttpSession().setAttribute("upload-error-msg", msg);
  125. }
  126. }
  127. /**
  128. * 读取用户头像
  129. * @param userId
  130. * @param req
  131. * @return
  132. * @throws SQLException
  133. */
  134. @Ok("raw:jpg")
  135. @At("/avatar")
  136. @GET
  137. public Object readAvatar(@Attr(scope = Scope.SESSION, value = "me")String userId, HttpServletRequest req) throws SQLException {
  138. UserProfile profile = Daos.ext(dao, FieldFilter.create(UserProfile.class, "^avatar$")).fetch(UserProfile.class, userId);
  139. if (profile == null || profile.getAvatar() == null) {
  140. return new File(req.getServletContext().getRealPath("/rs/user_avatar/none.jpg"));
  141. }
  142. return profile.getAvatar();
  143. }
  144. /**
  145. * 向用户邮箱发送验证邮件<br />
  146. * 注意, 因为emailKEY每次启动都是新的,所以重启Tomcat后,老的验证邮件就无效了哦. 真正用到时候,一般会存到一个文件或者数据库里面去
  147. * @param userId
  148. * @param req
  149. * @return
  150. */
  151. @At("/active/mail")
  152. @POST
  153. public Object activeMail(@Attr(scope = Scope.SESSION, value = "me")String userId, HttpServletRequest req) {
  154. NutMap re = new NutMap();
  155. UserProfile profile = get(userId);
  156. if (Strings.isBlank(profile.getEmail())) {
  157. return re.setv("ok", false).setv("msg", "你还没有填邮箱啊!");
  158. }
  159. String token = String.format("%s,%s,%s", userId, profile.getEmail(), System.currentTimeMillis());
  160. token = Toolkit._3DES_encode(emailKEY, token.getBytes());
  161. String url = req.getRequestURL() + "?token=" + token;
  162. String html = "<div>如果无法点击,请复制链接到浏览器中打开<p />验证链接 %s</div>";
  163. html = String.format(html, url, url);
  164. try {
  165. boolean ok = emailService.send(profile.getEmail(), "XXX 验证邮件 by Luxnk", html);
  166. if (!ok) {
  167. return re.setv("ok", false).setv("msg", "发送失败");
  168. }
  169. } catch (Throwable e) {
  170. log.debug("发送邮件失败", e);
  171. return re.setv("ok", false).setv("msg", "发送失败");
  172. }
  173. return re.setv("ok", true);
  174. }
  175. /**
  176. * 验证用户邮箱
  177. * @param token
  178. * @param session
  179. * @return
  180. */
  181. @Filters // 不需要登录
  182. @At("/active/mail")
  183. @GET
  184. @Ok("raw") // 为了简单起见,这里直接显示验证结果就好了
  185. public String activeMailCallback(@Param("token")String token, HttpSession session) {
  186. if (Strings.isBlank(token)) {
  187. return "请不要直接访问这个链接!!!";
  188. }
  189. if (token.length() < 10) {
  190. return "非法token";
  191. }
  192. try {
  193. token = Toolkit._3DES_decode(emailKEY, Toolkit.hexstr2bytearray(token));
  194. if (token == null)
  195. return "非法token";
  196. String[] tmp = token.split(",", 3);
  197. if (tmp.length != 3 || tmp[0].length() == 0 || tmp[1].length() == 0 || tmp[2].length() == 0)
  198. return "非法token";
  199. long time = Long.parseLong(tmp[2]);
  200. if (System.currentTimeMillis() - time > 10 * 60 * 1000) {
  201. return "该验证链接已经超时";
  202. }
  203. String userId = tmp[0];
  204. Cnd cnd = Cnd.where("userId", "=", userId).and("email", "=", tmp[1]);
  205. int re = dao.update(UserProfile.class, Chain.make("emailChecked", true), cnd);
  206. if (re == 1) {
  207. return "验证成功";
  208. }
  209. return "验证失败!请重新验证!!";
  210. } catch (Throwable e) {
  211. log.debug("检查token时出错", e);
  212. return "非法token";
  213. }
  214. }
  215. }