Переглянути джерело

用户头像上传及显示

Luxnk 7 роки тому
батько
коміт
4faa64e77a

+ 1 - 1
conf/custom/db.properties

@@ -1,5 +1,5 @@
 #mysql
-db.url=jdbc:mysql://127.0.0.1:3306/luxnktask
+db.url=jdbc:mysql://127.0.0.1:3306/luxnktask?useUnicode=true&characterEncoding=UTF-8
 db.username=root
 db.password=sa123456
 #db.validationQuery=select 1

+ 1 - 2
src/xyz/luxnk/lproject/MainSetup.java

@@ -28,8 +28,7 @@ public class MainSetup implements Setup {
         if (dao.count(UserInfo.class) == 0) {
             UserInfo userInfo = new UserInfo();
             userInfo.setUsername("Luxnk");
-            userInfo.setPassword("123456");
-            userInfo.setEmail("asd3115799@hotmail.com");
+            userInfo.setPassword("111111");
             userInfo.setCreateTime(new Date());
             userInfo.setUpdateTime(new Date());
             dao.insert(userInfo);

+ 7 - 7
src/xyz/luxnk/lproject/bean/UserInfo.java

@@ -5,7 +5,7 @@ import org.nutz.dao.entity.annotation.*;
 import java.util.Date;
 
 /**
- * 用户Pojo
+ * 用户基本信息Pojo
  * 对应user_info表
  */
 @Table("user_info")
@@ -24,8 +24,8 @@ public class UserInfo extends BasePojo {
     @Column
     private String salt;
 
-    @Column
-    private String email;
+    @One(target = UserProfile.class, field = "id", key = "userId")
+    private UserProfile profile;
 
     public String getId() {
         return id;
@@ -59,11 +59,11 @@ public class UserInfo extends BasePojo {
         this.salt = salt;
     }
 
-    public String getEmail() {
-        return email;
+    public UserProfile getProfile() {
+        return profile;
     }
 
-    public void setEmail(String email) {
-        this.email = email;
+    public void setProfile(UserProfile profile) {
+        this.profile = profile;
     }
 }

+ 105 - 0
src/xyz/luxnk/lproject/bean/UserProfile.java

@@ -0,0 +1,105 @@
+package xyz.luxnk.lproject.bean;
+
+import org.nutz.dao.entity.annotation.Column;
+import org.nutz.dao.entity.annotation.Id;
+import org.nutz.dao.entity.annotation.Name;
+import org.nutz.dao.entity.annotation.Table;
+import org.nutz.json.JsonField;
+
+/**
+ * 用户详细信息Pojo
+ */
+@Table("user_profile")
+public class UserProfile extends BasePojo {
+
+    //关联的用户ID
+    @Name
+    @Column("uid")
+    private String userId;
+
+    @Column
+    private String nickname;
+
+    @Column
+    private String email;
+
+    @Column("email_checked")
+    private boolean emailChecked;
+
+    @Column
+    @JsonField(ignore = true)
+    private byte[] avatar;
+
+    @Column
+    private String gender;
+
+    @Column
+    private String description;
+
+    @Column
+    private String location;
+
+    public String getUserId() {
+        return userId;
+    }
+
+    public void setUserId(String userId) {
+        this.userId = userId;
+    }
+
+    public String getNickname() {
+        return nickname;
+    }
+
+    public void setNickname(String nickname) {
+        this.nickname = nickname;
+    }
+
+    public String getEmail() {
+        return email;
+    }
+
+    public void setEmail(String email) {
+        this.email = email;
+    }
+
+    public boolean isEmailChecked() {
+        return emailChecked;
+    }
+
+    public void setEmailChecked(boolean emailChecked) {
+        this.emailChecked = emailChecked;
+    }
+
+    public byte[] getAvatar() {
+        return avatar;
+    }
+
+    public void setAvatar(byte[] avatar) {
+        this.avatar = avatar;
+    }
+
+    public String getGender() {
+        return gender;
+    }
+
+    public void setGender(String gender) {
+        this.gender = gender;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public String getLocation() {
+        return location;
+    }
+
+    public void setLocation(String location) {
+        this.location = location;
+    }
+}

+ 24 - 2
src/xyz/luxnk/lproject/module/UserModule.java

@@ -1,9 +1,11 @@
 package xyz.luxnk.lproject.module;
 
+import org.nutz.aop.interceptor.ioc.TransAop;
 import org.nutz.dao.Cnd;
 import org.nutz.dao.Dao;
 import org.nutz.dao.QueryResult;
 import org.nutz.dao.pager.Pager;
+import org.nutz.ioc.aop.Aop;
 import org.nutz.ioc.loader.annotation.Inject;
 import org.nutz.ioc.loader.annotation.IocBean;
 import org.nutz.lang.Strings;
@@ -11,6 +13,7 @@ import org.nutz.lang.util.NutMap;
 import org.nutz.mvc.annotation.*;
 import org.nutz.mvc.filter.CheckSession;
 import xyz.luxnk.lproject.bean.UserInfo;
+import xyz.luxnk.lproject.bean.UserProfile;
 
 import javax.servlet.http.HttpSession;
 import java.util.Date;
@@ -120,6 +123,11 @@ public class UserModule extends BaseModule {
         return re.setv("ok", true).setv("data", userInfo);
     }
 
+    /**
+     * 更新用户
+     * @param userInfo
+     * @return
+     */
     @At
     public Object update(@Param("..")UserInfo userInfo) {
        NutMap re = new NutMap();
@@ -134,15 +142,29 @@ public class UserModule extends BaseModule {
        return re.setv("ok", true);
     }
 
+    /**
+     * 删除用户
+     * @param id
+     * @param me
+     * @return
+     */
     @At
-    public Object delete(@Param("id")int id, @Attr("me")int me) {
-        if (me == id) {
+    @Aop(TransAop.READ_COMMITTED)
+    public Object delete(@Param("id")String id, @Attr("me")String me) {
+        if (me.equals(id)) {
             return new NutMap().setv("ok", false).setv("msg", "不能删除当前用户!");
         }
         dao.delete(UserInfo.class, id); // 再严谨一些的话,需要判断结果是否为>0
+        dao.clear(UserProfile.class, Cnd.where("userId", "=", id));
         return new NutMap().setv("ok", true);
     }
 
+    /**
+     * 查询用户
+     * @param name
+     * @param pager
+     * @return
+     */
     @At
     public Object query(@Param("name")String name, @Param("..")Pager pager) {
         Cnd cnd = Strings.isBlank(name)? null : Cnd.where("name", "like", "%" + name + "%");

+ 153 - 0
src/xyz/luxnk/lproject/module/UserProfileModule.java

@@ -0,0 +1,153 @@
+package xyz.luxnk.lproject.module;
+
+import org.nutz.dao.DaoException;
+import org.nutz.dao.FieldFilter;
+import org.nutz.dao.util.Daos;
+import org.nutz.img.Images;
+import org.nutz.ioc.loader.annotation.IocBean;
+import org.nutz.log.Log;
+import org.nutz.log.Logs;
+import org.nutz.mvc.Mvcs;
+import org.nutz.mvc.Scope;
+import org.nutz.mvc.adaptor.JsonAdaptor;
+import org.nutz.mvc.annotation.*;
+import org.nutz.mvc.filter.CheckSession;
+import org.nutz.mvc.impl.AdaptorErrorContext;
+import org.nutz.mvc.upload.TempFile;
+import org.nutz.mvc.upload.UploadAdaptor;
+import xyz.luxnk.lproject.bean.UserProfile;
+
+import javax.servlet.http.HttpServletRequest;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.sql.SQLException;
+import java.util.Date;
+
+@IocBean
+@At("/user/profile")
+@Filters(@By(type = CheckSession.class, args = {"me", "/"}))    // 检查当前Session是否带me这个属性
+public class UserProfileModule extends BaseModule {
+
+    public static final Log log = Logs.get();
+
+    @At("/")
+    @GET
+    @Ok("jsp:jsp.user.profile")
+    public UserProfile index(@Attr(scope = Scope.SESSION, value = "me")String userId) {
+        return get(userId);
+    }
+
+    /**
+     * 获取用户详细信息
+     * @param userId
+     * @return
+     */
+    @At
+    public UserProfile get(@Attr(scope = Scope.SESSION, value = "me")String userId) {
+        UserProfile profile = Daos.ext(dao, FieldFilter.locked(UserProfile.class, "avatar")).fetch(UserProfile.class, userId);
+        if (profile == null) {
+            profile = new UserProfile();
+            profile.setUserId(userId);
+            profile.setCreateTime(new Date());
+            profile.setUpdateTime(new Date());
+            dao.insert(profile);
+        }
+        return profile;
+    }
+
+    /**
+     * 更新用户详细信息
+     * @param profile
+     * @param userId
+     */
+    @At
+    @AdaptBy(type = JsonAdaptor.class)
+    @Ok("void")
+    public void update(@Param("..")UserProfile profile, @Attr(scope = Scope.SESSION, value = "me")String userId) {
+        if (profile == null)
+            return;
+        profile.setUserId(userId);  // 修正userId,防止恶意修改其他用户信息
+        profile.setUpdateTime(new Date());
+        profile.setAvatar(null);    // 不准通过这个方法更新
+        UserProfile old = get(userId);
+
+        // 检查email相关的更新
+        if (old.getEmail() == null) {
+
+            // 老的邮箱为null,所以新邮箱的肯定为未检查状态
+            profile.setEmailChecked(false);
+        } else {
+            if (profile.getEmail() == null) {
+                profile.setEmail(old.getEmail());
+                profile.setEmailChecked(old.isEmailChecked());
+            } else if (! profile.getEmail().equals(old.getEmail())) {
+
+                // 设置新邮箱的场合,邮箱状态设置为未检查状态
+                profile.setEmailChecked(false);
+            } else {
+                profile.setEmailChecked(old.isEmailChecked());
+            }
+        }
+
+        Daos.ext(dao, FieldFilter.create(UserProfile.class, null, "avatar", true)).update(profile);
+    }
+
+    /**
+     * 上传用户头像
+     * @param tf
+     * @param userId
+     * @param err
+     */
+    @AdaptBy(type = UploadAdaptor.class, args = {"${app.root}/WEB-INF/tmp/user_avatar", "8192", "utf-8", "20000", "1024000"})
+    @POST
+    @Ok(">>:/user/profile")
+    @At("/avatar")
+    public void uploadAvatar(@Param("file")TempFile tf, @Attr(scope = Scope.SESSION, value = "me")String userId, AdaptorErrorContext err) {
+        String msg = null;
+        if (err != null && err.getAdaptorErr() != null) {
+            msg = "文件大小不符合规定";
+        } else if (tf == null) {
+            msg = "空文件";
+        } else {
+            UserProfile profile = get(userId);
+            try {
+                BufferedImage image = Images.read(tf.getFile());
+                image = Images.zoomScale(image, 128, 128, Color.WHITE);
+                ByteArrayOutputStream out = new ByteArrayOutputStream();
+                Images.writeJpeg(image, out, 0.8f);
+                profile.setAvatar(out.toByteArray());
+                dao.update(profile, "^avatar$");
+            } catch (DaoException e) {
+                log.info("System Error", e);
+                msg = "系统错误";
+            } catch (Throwable e) {
+                msg = "图片格式错误";
+            }
+        }
+
+        if (msg != null) {
+            Mvcs.getHttpSession().setAttribute("upload-error-msg", msg);
+        }
+    }
+
+    /**
+     * 读取用户头像
+     * @param userId
+     * @param req
+     * @return
+     * @throws SQLException
+     */
+    @Ok("raw:jpg")
+    @At("/avatar")
+    @GET
+    public Object readAvatar(@Attr(scope = Scope.SESSION, value = "me")String userId, HttpServletRequest req) throws SQLException {
+        UserProfile profile = Daos.ext(dao, FieldFilter.create(UserProfile.class, "^avatar$")).fetch(UserProfile.class, userId);
+        if (profile == null || profile.getAvatar() == null) {
+            return new File(req.getServletContext().getRealPath("/rs/user_avatar/none.jpg"));
+        }
+        return profile.getAvatar();
+    }
+
+}

+ 1 - 2
src/xyz/luxnk/lproject/util/SnowflakeIdWorker.java

@@ -141,8 +141,7 @@ public class SnowflakeIdWorker implements RunMethod {
 
     @Override
     public Object run(List<Object> fetchParam) {
-        String id = nextId() + "";
-        System.out.println("看这里!!!!!!!!!!!!!!!!!!!! " + id);
+        String id = "L" + nextId();
         return id;
     }
 

+ 3 - 3
web/WEB-INF/jsp/user/list.jsp

@@ -52,8 +52,8 @@
                         var user = data.list[i];
                         console.log(user);
                         var tmp = '\n<p>' + user.id + ' ' + user.username
-                            + '<button onclick="user_update(' + user.id + ');">修改</button>'
-                            + '<button onclick="user_update(' + user.id + ');">删除</button>'
+                            + '<button onclick="user_update(\'' + user.id + '\');">修改</button>'
+                            + '<button onclick="user_delete(\'' + user.id + '\');">删除</button>'
                             + '</p>';
                         list_html += tmp;
                     }
@@ -104,7 +104,7 @@
             var s = prompt('请输入y确认删除');
             if (s == 'y') {
                 $.ajax({
-                    url: base + '/user/dalete',
+                    url: base + '/user/delete',
                     data: {'id': userId},
                     dataType: 'json',
                     success: function (data) {

+ 97 - 0
web/WEB-INF/jsp/user/profile.jsp

@@ -0,0 +1,97 @@
+<%--
+  Created by IntelliJ IDEA.
+  User: Administrator
+  Date: 2018/4/10 0010
+  Time: 14:12
+  To change this template use File | Settings | File Templates.
+--%>
+<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" trimDirectiveWhitespaces="true" %>
+<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
+<html>
+<head>
+    <title>用户详情页</title>
+    <script type="text/javascript" src="http://cdn.staticfile.org/jquery/1.8.3/jquery.min.js"></script>
+</head>
+<body>
+
+    <div>
+        <div>
+            头像 <img alt="用户头像" src="${base}/user/profile/avatar" />
+            <p />
+            <form action="${base}/user/profile/avatar" method="post" enctype="multipart/form-data">
+                头像文件 <input type="file" name="file" />
+                <button type="submit">更新头像</button>
+            </form>
+            <span style="color: #f00">
+                <%
+                    if (session.getAttribute("upload-error-msg") != null) {
+                        String msg = session.getAttribute("upload-error-msg").toString();
+                        out.print(msg);
+                        session.removeAttribute("upload-error-msg");
+                    }
+                %>
+            </span>
+            <p />
+        </div>
+    </div>
+    <div>
+        <form action="#" id="user_profile" method="post">
+            <div>
+                id: <c:out value="${obj.userId}"></c:out><p />
+            </div>
+            <div>
+                昵称:<input name="nickname" value="${obj.nickname}" /><p />
+            </div>
+            <div>
+                邮箱:<input name="email" value="${obj.email}"><p />
+            </div>
+            <div>
+                邮箱验证状态:<c:out value="${obj.emailChecked}"></c:out><p />
+            </div>
+            <div>
+                性别:<input name="gender" value="${obj.gender}"><p />
+            </div>
+            <div>
+                个性签名:<input name="description" value="${obj.description}"><p />
+            </div>
+            <div>
+                地理位置:<input name="location" value="${obj.location}"><p />
+            </div>
+        </form>
+        <button type="button" id="user_profile_btn">更新</button>
+    </div>
+
+    <script>
+        var base = '${base}';
+        $.fn.serializeObject = function () {
+            var o = {};
+            var a = this.serializeArray();
+            $.each(a, function () {
+                if (o[this.name] !== undefined) {
+                    if (! o[this.name].push) {
+                        o[this.name] = [ o[this.name] ];
+                    }
+                    o[this.name].push(this.value || '');
+                } else {
+                    o[this.name] = this.value || '';
+                }
+            });
+            return o;
+        }
+
+        $(function () {
+            $('#user_profile_btn').click(function () {
+                $.ajax({
+                    url: base + '/user/profile/update',
+                    type: 'POST',
+                    data: JSON.stringify($('#user_profile').serializeObject()),
+                    success: function () {
+                        location.reload();
+                    }
+                });
+            });
+        });
+    </script>
+
+</body>
+</html>

BIN
web/WEB-INF/lib/javax.servlet.jsp.jstl-api-1.2.1.jar


BIN
web/WEB-INF/lib/taglibs-standard-impl-1.2.5.jar


BIN
web/WEB-INF/lib/taglibs-standard-jstlel-1.2.5.jar


BIN
web/WEB-INF/lib/taglibs-standard-spec-1.2.5.jar


+ 2 - 0
web/index.jsp

@@ -16,6 +16,8 @@
     </div>
     <div id="user_info_div">
       <p id="userInfo"></p>
+      <a href="${base}/user">用户列表</a><br />
+      <a href="${base}/user/profile">个人信息</a><br />
       <a href="${base}/user/logout">登出</a>
     </div>
 

BIN
web/rs/user_avatar/none.jpg