AdminEAP

                         AdminEAP框架

1、概述

AdminEAP为本人基于AdminLTE改造的后台管理框架,包含了基本的系统管理功能和各种交互demo,项目已经开源到Github,并部署到阿里云。

Github : https://github.com/bill1012/AdminEAP

AdminEAP DEMO: http://www.admineap.com

本文介绍在AdminEAP框架中使用fullAvatarEditor实现用户头像上传的功能,代码已经在Github上。

头像上传

2、实现思路

新增用户时,保存图片的id,保存用户时,将头像和用户绑定,并修改头像名称
修改时,直接绑定用户和头像,如果以前有头像,将之前的头像文件删除

3、实现代码

用户编辑界面(新增和修改共用) user_page_edit.html

<section class="content-header">
    <h1>
        <span>用户管理</span>
        <small>新增</small>
    </h1>
    <ol class="breadcrumb">
        <li><a href="#"><i class="fa fa-dashboard"></i> 首页</a></li>
        <li><a href="#">系统管理</a></li>
        <li class="active">用户管理</li>
    </ol>
</section>
<section class="content">
    <div class="row">
        <div class="col-xs-12">
            <div class="box box-info">
            <form id="user-form" name="user-form" class="form-horizontal">
                <input type="hidden" name="id">
                <input type="hidden" name="version">
                <input type="hidden" name="isSuperAdmin">
                <input type="hidden" name="createDateTime" data-flag="date" data-format="yyyy-MM-dd HH:mm:ss">
                <input type="hidden" name="deleted">
                <input type='hidden' value='${CSRFToken}' id='csrftoken'>
                <input type="hidden" id="avatarId" name="avatarId">
                <div class="box-header">
                    <div class="col-xs-12 text-center">
                       <div class="avatar-container text-center">
                           <img src="${basePath}/resources/common/images/avatar.jpg" id="avatarImg" class="avatar-img"/>
                       </div>
                        <div>
                           <button type="button" class="btn btn-sm btn-camera" data-btn-type="upload" ><i class="fa fa-camera">&nbsp;上传/更改头像</i></button>
                        </div>
                    </div>
                </div>
                <div class="box-body">
                    <div class="col-md-6">
                        <div class="form-group">
                            <label for="name" class="col-sm-3 control-label">姓名</label>
                            <div class="col-sm-8">
                                <input type="text" class="form-control" id="name" name="name" placeholder="姓名">
                            </div>
                        </div>
                        <div class="form-group">
                            <label for="birthday" class="col-sm-3 control-label">出生日期</label>
                            <div class="input-group date col-sm-8">
                                <div class="input-group-addon">
                                    <i class="fa fa-calendar"></i>
                                </div>
                                <input type="text" class="form-control" data-flag="datepicker" data-format="yyyy-MM-dd"
                                       id="birthday" name="birthday"
                                       placeholder="出生日期">
                            </div>
                        </div>
                        <div class="form-group">
                            <label for="telphone" class="col-sm-3 control-label">座机</label>

                            <div class="col-sm-8">
                                <input type="text" class="form-control" id="telphone" name="telphone" placeholder="座机">
                            </div>
                        </div>
                        <div class="form-group">
                            <label for="email" class="col-sm-3 control-label">Email</label>

                            <div class="col-sm-8">
                                <input type="text" class="form-control" id="email" name="email" placeholder="Email">
                            </div>
                        </div>
                    </div>
                    <div class="col-md-6">
                        <div class="form-group">
                            <label class="col-sm-3 control-label">性别</label>

                            <div class="col-sm-8">
                                <label class="control-label"> <input type="radio" name="sex" data-flag="icheck"
                                                                     class="flat-red" value="1"></label> &nbsp; <label class="control-label"> <input type="radio" name="sex"
                                                                                     data-flag="icheck" class="flat-red"
                                                                                     value="0"></label>
                            </div>
                        </div>
                        <div class="form-group">
                            <label for="loginName" class="col-sm-3 control-label">登录名</label>

                            <div class="col-sm-8">
                                <input type="text" class="form-control" id="loginName" name="loginName"
                                       placeholder="登录名">
                            </div>
                        </div>
                        <div class="form-group">
                            <label for="mobile" class="col-sm-3 control-label">手机</label>

                            <div class="col-sm-8">
                                 <input type="text" class="form-control" id="mobile" name="mobile" placeholder="手机">
                            </div>
                        </div>
                        <div class="form-group">
                            <label for="qq" class="col-sm-3 control-label">QQ</label>
                            <div class="col-sm-8">
                                <input type="text" class="form-control" id="qq" name="qq" placeholder="QQ">
                            </div>
                        </div>
                    </div>
                </div>
                <!-- /.box-body -->
                <div class="box-footer text-right">
                    <!--以下两种方式提交验证,根据所需选择-->
                    <button type="button" class="btn btn-default" data-btn-type="cancel" >取消 </button>
                    <button type="submit" class="btn btn-primary" data-btn-type="save">提交</button>
                </div>
                <!-- /.box-footer -->
            </form>
            </div>
        </div>
    </div>
</section>
</div>
<script>
    //tableId,queryId,conditionContainer
    var form = null;
    var id = "${id?default(0)}";
    $(function () {
        //数据校验
        $("#user-form").bootstrapValidator({
            message: '请输入有效值',
            feedbackIcons: {
                valid: 'glyphicon glyphicon-ok',
                invalid: 'glyphicon glyphicon-remove',
                validating: 'glyphicon glyphicon-refresh'
            },
            submitHandler: function (validator, userform, submitButton) {
                modals.confirm('确认保存?', function () {
                    //Save Data,对应'submit-提交'
                    var params = form.getFormSimpleData();
                    ajaxPost(basePath + '/user/save', params, function (data, status) {
                        if (data.success) {
                            if (id != "0") {//更新
                               gotolist(id);
                            } else {//新增
                                //modals.info("数据保存成功");
                                gotolist();
                            }
                        }
                    });
                });
            },
            fields: {
                name: {
                    validators: {
                        notEmpty: {
                            message: '请输入姓名'
                        }
                    }
                },
                sex: {
                    validators: {
                        notEmpty: {
                            message: '请选择性别'
                        }
                    }
                },
                birthday: {
                    validators: {
                        notEmpty: {
                            message: '请输入出生日期'
                        },
                        date: {
                            format: $(this).data("format"),
                            message: '请输入有效日期'
                        }
                    }
                },
                loginName: {
                    validators: {
                        notEmpty: {
                            message: '请输入登录名'
                        }
                    }
                },
                email: {
                    validators: {
                        notEmpty: {
                            message: '请输入邮件',
                        },
                        emailAddress: {
                            message: '非法的邮件格式',
                        }

                    }
                }
            }
        });
        //初始化控件
        form = $("#user-form").form();
        //回填id
        if (id != "0") {
            ajaxPost(basePath + "/user/get", {id: id}, function (data) {
                form.initFormData(data);
                $(".content-header h1 small").html("编辑用户【"+data.name+"】");
                //头像回填
                ajaxPost(basePath+"/user/getAvatar",{userId:id},function(result){
                    setAvatar(result.id,result.src,false);
                })
            })
        }

        //cancel
        $("[data-btn-type='cancel']").click(function () {
           gotolist();
        })

        $("[data-btn-type='upload']").click(function(){
            uploadAvatar();
        })
    });

    function gotolist(id){
        window.loadPage(basePath+"/user/page/list?id="+id);
    }

    var avatarWin="avatarWin";
    function uploadAvatar(){
        modals.openWin({
            winId:avatarWin,
            title:'上传头像',
            width:'700px',
            url:basePath+"/user/avatar?userId="+id
        });
    }


    function resetForm() {
        form.clearForm();
        $("#user-form").data('bootstrapValidator').resetForm();
    }

    function setAvatar(avatar_id,avatar_url,isAdd){
        $("#avatarImg").attr("src",basePath+avatar_url);
        //如果是新增 绑定用户
        if(isAdd){
            $("#avatarId").val(avatar_id);
        }else{
            $("#avatarId").val(null);
        }
    }
</script>

头像上传界面 user_avatar.html

<script type="text/javascript" src="${basePath}/resources/common/libs/avatar/swfobject.js"></script>
<script type="text/javascript" src="${basePath}/resources/common/libs/avatar/fullAvatarEditor.js"></script>
<div class="modal-header">
    <button type="button" class="close" data-dismiss="modal" aria-hidden="true"><li class="fa fa-remove"></li></button>
    <h5 class="modal-title">新增用户</h5>
</div>

<div class="modal-body">
        <div class="box-body">
            <input type="hidden" value="${userId?default('')}" name="userId" id="userId"/>
            <div style="width: 680px;height:360px;margin: 0 auto;">
                <div>
                    <p id="swfContainer">
                        本组件需要安装Flash Player后才可使用,请从
                        <a href="http://www.adobe.com/go/getflashplayer">这里</a>下载安装。
                    </p>
                </div>
            </div>
        </div>
    <div class="box-footer text-right">
        <button type="button" class="btn btn-info btn-sm" data-btn-type="cancel" data-dismiss="modal"><i class="fa fa-remove">&nbsp;&nbsp;取消</i> </button>
    </div>
</div>
<script>

    if (navigator.userAgent.indexOf('Firefox') >= 0){
        avatarPath='';
    }
    swfobject.addDomLoadEvent(function () {
        var swf = new fullAvatarEditor("swfContainer", {
                    id: 'swfUploader',
                    upload_url: basePath+'/file/avatarUpload?userId='+$("#userId").val(),
                    src_url:avatarPath,
                    src_upload:0,
                    src_size:"5MB",
                    avatar_sizes:"160*160",
                    avatar_sizes_desc:"160*160像素",
                    browse_tip:"仅支持JPG、JPEG、GIF、PNG格式的图片文件\n文件不能大于5MB",
                    src_size_over_limit:'文件大小({0})超出限制(5MB)\n请重新上传'
                }, function (msg) {
                    switch(msg.code)
                    {
                            /**
                             case 1 : alert("页面成功加载了组件!");break;
                             case 2 : alert("已成功加载默认指定的图片到编辑面板。");break;
                             case 3 :
                             if(msg.type == 0)
                             {
                                 alert("摄像头已准备就绪且用户已允许使用。");
                             }
                             else if(msg.type == 1)
                             {
                                 alert("摄像头已准备就绪但用户未允许使用!");
                             }
                             else
                             {
                                 alert("摄像头被占用!");
                             }
                             break;
                             **/
                        case 5 :
                            if(msg.type == 0)
                            {
                                var isAdd=true;
                                if($("#userId").val()!=''&&$("#userId").val()!='0'){
                                    isAdd=false;
                                }
                                if(msg.content.sourceUrl)
                                {
                                    modals.correct("头像已成功保存");
                                    setAvatar(msg.content.msg,msg.content.avatarUrls[i],isAdd);
                                }
                                for(var i=0;i<msg.content.avatarUrls.length;i++){
                                    setAvatar(msg.content.msg,msg.content.avatarUrls[i],isAdd);
                                }
                            }
                            else if(msg.type==1){
                                modals.error('头像上传失败,原因:' + msg.content.msg);
                            }
                            else if(msg.type==2){
                                modals.error('头像上传失败,原因:指定的上传地址不存在或有问题!');
                            }
                            else if(msg.type==3){
                                modals.error('头像上传失败,原因:发生了安全性错误!请联系站长添加crossdomain.xml到网站根目录。');
                            }
                                modals.hideWin("avatarWin");
                            break;
                    }
                }
        );
    });
</script>

头像上传后台处理

 @RequestMapping("/avatarUpload")
    @ResponseBody
    public AvatarResult avatarUpload(String userId, HttpServletRequest httpRequest, HttpSession session) throws Exception {

        MultipartHttpServletRequest request = (MultipartHttpServletRequest) httpRequest;
        Map<String, MultipartFile> fileMap = request.getFileMap();
        String contentType = request.getContentType();
        if (contentType.indexOf("multipart/form-data") >= 0) {
            AvatarResult result = new AvatarResult();
            result.setAvatarUrls(new ArrayList());
            result.setSuccess(false);
            result.setMsg("Failure!");

            // 定义一个变量用以储存当前头像的序号
            int avatarNumber = 1;
            User user = uploaderService.get(User.class, userId);
            if (user == null) {
                user = new User();
                user.setName("new");
            }
            // 文件名
            String fileName = user.getName() + "_" + (new Date()).getTime() + ".jpg";
            String relPath = PropertiesUtil.getValue("avatarPath");
            String dirPath = request.getRealPath("/");

            String initParams = "";

            BufferedInputStream inputStream;
            BufferedOutputStream outputStream;
            for (Iterator<Map.Entry<String, MultipartFile>> it = fileMap.entrySet().iterator(); it.hasNext(); avatarNumber++) {
                Map.Entry<String, MultipartFile> entry = it.next();
                MultipartFile mFile = entry.getValue();
                String fieldName = entry.getKey();
                Boolean isSourcePic = fieldName.equals("__source"); // 是否是原始图片域名称
                // 文件名,如果是本地或网络图片为原始文件名(不含扩展名)、如果是摄像头拍照则为 *FromWebcam
                // String name = fileItem.getName();
                // 当前头像基于原图的初始化参数(即只有上传原图时才会发送该数据),用于修改头像时保证界面的视图跟保存头像时一致,提升用户体验度。
                // 修改头像时设置默认加载的原图url为当前原图url+该参数即可,可直接附加到原图url中储存,不影响图片呈现。
                if (fieldName.equals("__initParams")) {
                    inputStream = new BufferedInputStream(mFile.getInputStream());
                    byte[] bytes = new byte[mFile.getInputStream().available()];
                    inputStream.read(bytes);
                    initParams = new String(bytes, "UTF-8");
                    inputStream.close();
                } else if (isSourcePic || fieldName.startsWith("__avatar")) {
                    String virtualPath = dirPath + relPath + "\\" + fileName;
                    if (avatarNumber > 1) {
                        fileName = avatarNumber + fileName;
                        virtualPath = dirPath + relPath + "\\" + fileName;
                    }
                    // 原始图片(file 域的名称:__source,如果客户端定义可以上传的话,可在此处理)。
                    if (isSourcePic) {
                        fileName = "source" + fileName;
                        virtualPath = dirPath + relPath + "\\" + fileName;
                        result.setSourceUrl(relPath + "/" + fileName);
                    }
                    // 头像图片(file 域的名称:__avatar1,2,3...)。
                    else {
                        result.getAvatarUrls().add(relPath + "/" + fileName);
                    }

                    inputStream = new BufferedInputStream(mFile.getInputStream());
                    outputStream = new BufferedOutputStream(new FileOutputStream(virtualPath.replace("/", "\\")));
                    Streams.copy(inputStream, outputStream, true);
                    inputStream.close();
                    outputStream.flush();
                    outputStream.close();
                    // 保存图片信息
                    result.setMsg(uploaderService.saveAvatar(userId, fileName, relPath + File.separator + fileName, dirPath));
                }

            }
            if (result.getSourceUrl() != null) {
                result.setSourceUrl(result.getSourceUrl() + initParams);
            }
            result.setSuccess(true);
            return result;
        }
        return null;
    }

头像上传处理结果实体 AvatarResult.java

package com.cnpc.framework.base.pojo;

import java.util.ArrayList;

/**
 * Created by billJiang on 2016/12/6.
 * e-mail:jrn1012@petrochina.com.cn qq:475572229
 */
public class AvatarResult {
        /**
         * 表示图片是否已上传成功。
         */
        private Boolean success;
        /**
         * 自定义的附加消息。
         */
        private String msg;
        /**
         * 表示原始图片的保存地址。
         */
        private String sourceUrl;
        /**
         * 表示所有头像图片的保存地址,该变量为一个数组。
         */
        private ArrayList avatarUrls;
        public Boolean getSuccess() {
            return success;
        }
        public void setSuccess(Boolean success) {
            this.success = success;
        }
        public String getMsg() {
            return msg;
        }
        public void setMsg(String msg) {
            this.msg = msg;
        }
        public String getSourceUrl() {
            return sourceUrl;
        }
        public void setSourceUrl(String sourceUrl) {
            this.sourceUrl = sourceUrl;
        }
        public ArrayList getAvatarUrls() {
            return avatarUrls;
        }
        public void setAvatarUrls(ArrayList avatarUrls) {
            this.avatarUrls = avatarUrls;
        }


}

头像保存 uploaderService–>saveAvatar方法

public String saveAvatar(String userId, String fileName, String filePath, String dirPath) {
        UserAvatar avatar = null;
        if(!StrUtil.isEmpty(userId)&&!userId.equals("0"))
                avatar=userService.getAvatarByUserId(userId);
        String avatar_id=avatar==null?null:avatar.getId();
        //图片替换
        if (avatar != null) {
            File file = new File(dirPath + avatar.getSrc());
            if (file.exists())
                file.delete();
            avatar.setName(fileName);
            avatar.setSrc(filePath);
            avatar.setUpdateDateTime(new Date());
            this.update(avatar);
        }
        // 新增图片
        else {
            avatar = new UserAvatar();
            avatar.setName(fileName);
            avatar.setSrc(filePath);
            avatar.setCreateDateTime(new Date());
            avatar.setUserId(userId);
            avatar_id=this.save(avatar).toString();
        }
        return avatar_id;
    }

用户新增关联头像 userService–>updateUserAvatar方法

@Override
    public void updateUserAvatar(User user,String dirPath) {
       if(StrUtil.isEmpty(user.getAvatarId()))
           return;
        UserAvatar userAvatar=this.get(UserAvatar.class,user.getAvatarId());
        userAvatar.setUserId(user.getId());
        String src=userAvatar.getSrc();
        File file = new File(dirPath +src);
        String newPath=src.replaceAll("new",user.getName());
        if (file.exists()) {
            file.renameTo(new File(dirPath+newPath));
        }
        userAvatar.setSrc(newPath);
        userAvatar.setName(userAvatar.getName().replaceAll("new",user.getName()));
        this.update(userAvatar);
    }

实现结果
这里写图片描述

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐