zoukankan      html  css  js  c++  java
  • Java单体应用

    原文地址:http://www.work100.net/training/monolithic-project-iot-cloud-admin-manager-add.html
    更多教程:光束云 - 免费课程

    新增账户

    序号 文内章节 视频
    1 概述 -
    2 后端代码实现 -
    3 前端页面实现 -
    4 测试验证 -
    5 使用表单标签库 -
    6 使用表单验证 -
    7 实例源码 -

    请参照如上章节导航进行阅读

    1.概述

    本节实现 新增账户 功能,页面效果如下:

    2.后端代码实现

    为了降低耦合度,建议大家将新增编辑查看功能分开编码,不要混在一个方法中。

    我们现在演示的功能相对比较简单,但真正开展业务时功能会变得很复杂,如果代码混在一起,那么代码的复杂度也将成倍增长。

    接下来,我们来逐步重构 ManagerController 类。

    GET 方法

    @RequestMapping(value = "add", method = RequestMethod.GET)
    public String add() {
        return "auth/manager_add";
    }
    

    POST 方法

    @RequestMapping(value = "add", method = RequestMethod.POST)
    public String add(AuthManager authManager, Model model, RedirectAttributes redirectAttributes) {
        // 表单验证
        if (StringUtils.isBlank(authManager.getUserName())) {
            model.addAttribute("baseResult", BaseResult.fail("用户名不能空"));
            model.addAttribute("authManager", authManager);
            return "auth/manager_add";
        }
        if (authManager.getUserName().length() < 4 || authManager.getUserName().length() > 20) {
            model.addAttribute("baseResult", BaseResult.fail("用户名不能小于4位且不能大于20位"));
            model.addAttribute("authManager", authManager);
            return "auth/manager_add";
        }
        if (StringUtils.isBlank(authManager.getPassword())) {
            model.addAttribute("baseResult", BaseResult.fail("密码不能空且不能少于"));
            model.addAttribute("authManager", authManager);
            return "auth/manager_add";
        }
        if (authManager.getPassword().length() < 6 || authManager.getUserName().length() > 20) {
            model.addAttribute("baseResult", BaseResult.fail("密码不能小于6个位且不能大于20位"));
            model.addAttribute("authManager", authManager);
            return "auth/manager_add";
        }
        if (StringUtils.isBlank(authManager.getRoles())) {
            model.addAttribute("baseResult", BaseResult.fail("角色不能空"));
            model.addAttribute("authManager", authManager);
            return "auth/manager_add";
        }
    
        // 新增处理
        BaseResult baseResult = authManagerService.insert(authManager);
        if (baseResult.getStatus() == HttpUtils.HTTP_STATUS_CODE_OK) {
            redirectAttributes.addFlashAttribute("baseResult", baseResult);
            return "redirect:/auth/manager/list";
        } else {
            model.addAttribute("baseResult", baseResult);
            return "auth/manager_add";
        }
    }
    

    说明

    • 后端一定要对前端提交数据进行合法性验证,以便确保数据安全

    • 方法中使用了 BaseResultHttpUtils 两个类,下面将分别进行介绍

    BaseResult 类

    为了将操作结果更方便的传递给前端页面,我们引入一个通用的 BaseResult 类,代码如下:

    package net.work100.training.stage2.iot.cloud.commons.dto;
    
    import net.work100.training.stage2.iot.cloud.commons.utils.HttpUtils;
    
    import java.io.Serializable;
    
    /**
     * <p>Title: BaseResult</p>
     * <p>Description: </p>
     *
     * @author liuxiaojun
     * @date 2020-03-04 11:02
     * ------------------- History -------------------
     * <date>      <author>       <desc>
     * 2020-03-04   liuxiaojun     初始创建
     * -----------------------------------------------
     */
    public class BaseResult implements Serializable {
        private int status;
        private String message;
    
    
        public static BaseResult success() {
            return createResult(HttpUtils.HTTP_STATUS_CODE_OK, "成功");
        }
    
        public static BaseResult success(String message) {
            return createResult(HttpUtils.HTTP_STATUS_CODE_OK, message);
        }
    
        public static BaseResult fail() {
            return createResult(HttpUtils.HTTP_STATUS_CODE_INTERNAL_SERVER_ERROR, "失败");
        }
    
        public static BaseResult fail(String message) {
            return createResult(HttpUtils.HTTP_STATUS_CODE_INTERNAL_SERVER_ERROR, message);
        }
    
        public static BaseResult fail(int status, String message) {
            return createResult(status, message);
        }
    
        public int getStatus() {
            return status;
        }
    
        public void setStatus(int status) {
            this.status = status;
        }
    
        public String getMessage() {
            return message;
        }
    
        public void setMessage(String message) {
            this.message = message;
        }
    
        private static BaseResult createResult(int status, String message) {
            BaseResult baseResult = new BaseResult();
            baseResult.setStatus(status);
            baseResult.setMessage(message);
            return baseResult;
        }
    }
    

    类文件位置在 iot-cloud-commons 项目下的 net.work100.training.stage2.iot.cloud.commons.dto 类包下。

    HttpUtils 类

    BaseResult 的返回状态码构造一个通用类 HttpUtils,代码如下:

    package net.work100.training.stage2.iot.cloud.commons.utils;
    
    /**
     * <p>Title: Http状态码</p>
     * <p>Description: </p>
     * <p>Url: http://www.work100.net/training/monolithic-project-iot-cloud-admin.html</p>
     *
     * @author liuxiaojun
     * @date 2019-07-14 20:51
     * ------------------- History -------------------
     * <date>      <author>       <desc>
     * 2019-07-14   liuxiaojun     初始创建
     * -----------------------------------------------
     */
    public class HttpUtils {
    
        public static final int HTTP_STATUS_CODE_CONTINUE = 100;
        public static final int HTTP_STATUS_CODE_SWITCHING_PROTOCOLS = 101;
        public static final int HTTP_STATUS_CODE_OK = 200;
        public static final int HTTP_STATUS_CODE_CREATED = 201;
        public static final int HTTP_STATUS_CODE_ACCEPTED = 202;
        public static final int HTTP_STATUS_CODE_NON_AUTHORITATIVE_INFORMATION = 203;
        public static final int HTTP_STATUS_CODE_NO_CONTENT = 204;
        public static final int HTTP_STATUS_CODE_RESET_CONTENT = 205;
        public static final int HTTP_STATUS_CODE_PARTIAL_CONTENT = 206;
        public static final int HTTP_STATUS_CODE_MULTIPLE_CHOICES = 300;
        public static final int HTTP_STATUS_CODE_MOVED_PERMANENTLY = 301;
        public static final int HTTP_STATUS_CODE_MOVED_TEMPORARILY = 302;
        public static final int HTTP_STATUS_CODE_FOUND = 302;
        public static final int HTTP_STATUS_CODE_SEE_OTHER = 303;
        public static final int HTTP_STATUS_CODE_NOT_MODIFIED = 304;
        public static final int HTTP_STATUS_CODE_USE_PROXY = 305;
        public static final int HTTP_STATUS_CODE_TEMPORARY_REDIRECT = 307;
        public static final int HTTP_STATUS_CODE_BAD_REQUEST = 400;
        public static final int HTTP_STATUS_CODE_UNAUTHORIZED = 401;
        public static final int HTTP_STATUS_CODE_PAYMENT_REQUIRED = 402;
        public static final int HTTP_STATUS_CODE_FORBIDDEN = 403;
        public static final int HTTP_STATUS_CODE_NOT_FOUND = 404;
        public static final int HTTP_STATUS_CODE_METHOD_NOT_ALLOWED = 405;
        public static final int HTTP_STATUS_CODE_NOT_ACCEPTABLE = 406;
        public static final int HTTP_STATUS_CODE_PROXY_AUTHENTICATION_REQUIRED = 407;
        public static final int HTTP_STATUS_CODE_REQUEST_TIMEOUT = 408;
        public static final int HTTP_STATUS_CODE_CONFLICT = 409;
        public static final int HTTP_STATUS_CODE_GONE = 410;
        public static final int HTTP_STATUS_CODE_LENGTH_REQUIRED = 411;
        public static final int HTTP_STATUS_CODE_PRECONDITION_FAILED = 412;
        public static final int HTTP_STATUS_CODE_REQUEST_ENTITY_TOO_LARGE = 413;
        public static final int HTTP_STATUS_CODE_REQUEST_URI_TOO_LONG = 414;
        public static final int HTTP_STATUS_CODE_UNSUPPORTED_MEDIA_TYPE = 415;
        public static final int HTTP_STATUS_CODE_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
        public static final int HTTP_STATUS_CODE_EXPECTATION_FAILED = 417;
        public static final int HTTP_STATUS_CODE_INTERNAL_SERVER_ERROR = 500;
        public static final int HTTP_STATUS_CODE_NOT_IMPLEMENTED = 501;
        public static final int HTTP_STATUS_CODE_BAD_GATEWAY = 502;
        public static final int HTTP_STATUS_CODE_SERVICE_UNAVAILABLE = 503;
        public static final int HTTP_STATUS_CODE_GATEWAY_TIMEOUT = 504;
        public static final int HTTP_STATUS_CODE_HTTP_VERSION_NOT_SUPPORTED = 505;
    }
    

    类文件位置在 iot-cloud-commons 项目下的 net.work100.training.stage2.iot.cloud.commons.utils 类包下。

    AuthManagerService 服务接口

    重构 AuthManagerService 服务接口的 insert 方法,代码如下:

    /**
     * 新增
     *
     * @param authManager
     * @return
     */
    BaseResult insert(AuthManager authManager);
    

    AuthManagerServiceImpl 服务实现

    重构 AuthManagerServiceImpl 服务实现的 insert 方法,代码如下:

    @Override
    public BaseResult insert(AuthManager authManager) {
        if (authManagerDao.getByUserName(authManager.getUserName()) != null) {
            return BaseResult.fail("用户名已经存在");
        }
        try {
            // 生成 userKey
            authManager.setUserKey(generateUserKey(authManager.getUserName()));
    
            // 密码加密
            authManager.setPassword(EncryptionUtils.encryptPassword(EncryptionUtils.EncryptionType.MD5, authManager.getPassword()));
            authManager.setCreated(new Date());
            authManager.setUpdated(new Date());
    
            authManagerDao.insert(authManager);
            return BaseResult.success("新增账户成功");
        } catch (Exception ex) {
            return BaseResult.fail("未知错误");
        }
    }
    

    新增 generateUserKey 方法,实现 userKey 的生成逻辑,代码如下:

    /**
     * 生成 userKey
     *
     * @param userName 用户名
     * @return
     */
    private String generateUserKey(String userName) {
        String strDate = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss");
        String sourceUserKey = String.format("%s%s", userName.toLowerCase(), strDate);
        return EncryptionUtils.encryptText(EncryptionUtils.EncryptionType.MD5, sourceUserKey);
    }
    

    3.前端页面实现

    视图文件 manager_add.jsp

    views/auth/ 目录下增加一个 manager_add.jsp 视图文件,代码如下:

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <!DOCTYPE html>
    <html>
    <head>
        <title>新增账户 - 后台账户 | IoT-Admin</title>
        <jsp:include page="../includes/resources_head.jsp" />
    </head>
    <body class="hold-transition sidebar-mini">
    <div class="wrapper">
    
        <jsp:include page="../includes/layout_header.jsp" />
    
        <jsp:include page="../includes/layout_left.jsp" />
    
        <!-- Content Wrapper. Contains page content -->
        <div class="content-wrapper">
            <!-- Content Header (Page header) -->
            <div class="content-header">
                <div class="container-fluid">
                    <div class="row mb-2">
                        <div class="col-sm-6">
                            <h1 class="m-0 text-dark">新增账户</h1>
                        </div><!-- /.col -->
                        <div class="col-sm-6">
                            <ol class="breadcrumb float-sm-right">
                                <li class="breadcrumb-item"><a href="#">后台账户</a></li>
                                <li class="breadcrumb-item active">新增账户</li>
                            </ol>
                        </div><!-- /.col -->
                    </div><!-- /.row -->
                </div><!-- /.container-fluid -->
            </div>
            <!-- /.content-header -->
    
            <!-- Main content -->
            <div class="content">
                <div class="container-fluid">
                    <div class="row">
                        <div class="col">
                            <div class="card card-gray">
                                <!-- /.card-header -->
                                <!-- form start -->
                                <form action="/auth/manager/add" method="post">
                                    <div class="card-body">
                                        <div class="row">
                                            <div class="col-md-6">
                                                <div class="form-group">
                                                    <label for="userName">用户名</label>
                                                    <input type="text" class="form-control" id="userName" name="userName" placeholder="请输入用户名" value="${authManager.userName}">
                                                </div>
                                                <div class="form-group">
                                                    <label for="password">密码</label>
                                                    <input type="password" class="form-control" id="password" name="password" placeholder="请输入密码">
                                                </div>
                                                <div class="form-group">
                                                    <label for="status">状态</label>
                                                    <select class="form-control select2" style=" 100%;" id="status" name="status">
                                                        <option value="0" selected="selected">未激活</option>
                                                        <option value="1">激活</option>
                                                        <option value="2">锁定</option>
                                                        <option value="3">删除</option>
                                                    </select>
                                                </div>
                                            </div>
                                            <div class="col-md-6">
                                                <div class="form-group">
                                                    <label for="roles">角色</label>
                                                    <select class="select2" id="roles" name="roles" multiple="multiple" data-placeholder="请选择角色" style=" 100%;">
                                                        <option value="admin" ${authManager.roles.contains("admin")?"selected":""}>admin</option>
                                                        <option value="editor" ${authManager.roles.contains("editor")?"selected":""}>editor</option>
                                                    </select>
                                                </div>
                                                <div class="form-group">
                                                    <label for="superuser">是否超级用户</label>
                                                    <select class="form-control select2" id="superuser" name="superuser" style=" 100%;">
                                                        <option value="0" selected="selected">否</option>
                                                        <option value="1">是</option>
                                                    </select>
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                    <!-- /.card-body -->
    
                                    <div class="card-footer">
                                        <button type="submit" class="btn btn-primary">保存</button>
                                        <a href="/auth/manager/list" type="button" class="btn btn-default">返回列表</a>
                                    </div>
                                </form>
                            </div>
                            <!-- /.card -->
                        </div>
                    </div>
                </div>
                <!-- /.container-fluid -->
            </div>
            <!-- /.content -->
        </div>
        <!-- /.content-wrapper -->
    
        <jsp:include page="../includes/layout_footer.jsp" />
    </div>
    <!-- ./wrapper -->
    <jsp:include page="../includes/resources_body.jsp" />
    
    <script>
    $(function() {
        //Initialize Select2 Elements
        $('.select2').select2();
    
        //Initialize Select2 Elements
        $('.select2bs4').select2({
            theme: 'bootstrap4'
        });
    
        if (${baseResult.status != null && baseResult.status != 200}) {
            const Toast = Swal.mixin({
                toast: true,
                position: 'top',
                showConfirmButton: false,
                timer: 2000,
                timerProgressBar: true,
                onOpen: (toast) => {
                    toast.addEventListener('mouseenter', Swal.stopTimer)
                    toast.addEventListener('mouseleave', Swal.resumeTimer)
                }
            })
    
            Toast.fire({
                type: 'error',
                title: '${baseResult.message}'
            })
        }
    })
    </script>
    </body>
    </html>
    

    依赖脚本及控件

    文件末尾我们增加了一段 JS 脚本:

    如下代码是为了让 select 控件应用 Bootstrap4 样式:

    //Initialize Select2 Elements
    $('.select2').select2();
    
    //Initialize Select2 Elements
    $('.select2bs4').select2({
        theme: 'bootstrap4'
    });
    

    如下代码是为了将操作结果消息向用户更友好的展示出来:

    if (${baseResult.status != null && baseResult.status != 200}) {
        const Toast = Swal.mixin({
            toast: true,
            position: 'top',
            showConfirmButton: false,
            timer: 2000,
            timerProgressBar: true,
            onOpen: (toast) => {
                toast.addEventListener('mouseenter', Swal.stopTimer)
                toast.addEventListener('mouseleave', Swal.resumeTimer)
            }
        })
    
        Toast.fire({
            type: 'error',
            title: '${baseResult.message}'
        })
    }
    

    页面中用到的 select 控件和提示消息依赖了相关插件,其依赖插件的 CSSJS 分别在 resources_head.jsresources_body.js 中引入:

    resources_head.js 代码如下:

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <!-- Font Awesome Icons -->
    <link rel="stylesheet" href="/static/assets/plugins/fontawesome-free/css/all.min.css">
    
    <!-- iCheck for checkboxes and radio inputs -->
    <link rel="stylesheet" href="/static/assets/plugins/icheck-bootstrap/icheck-bootstrap.min.css">
    
    <!-- Select2 -->
    <link rel="stylesheet" href="/static/assets/plugins/select2/css/select2.min.css">
    <link rel="stylesheet" href="/static/assets/plugins/select2-bootstrap4-theme/select2-bootstrap4.min.css">
    
    <!-- SweetAlert2 -->
    <link rel="stylesheet" href="/static/assets/plugins/sweetalert2/sweetalert2.min.css">
    
    <!-- Theme style -->
    <link rel="stylesheet" href="/static/assets/css/adminlte.min.css">
    <link rel="icon" href="/static/assets/img/favicon.ico">
    

    resources_body.js 代码如下:

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <!-- REQUIRED SCRIPTS -->
    
    <!-- jQuery -->
    <script src="/static/assets/plugins/jquery/jquery.min.js"></script>
    <!-- Bootstrap -->
    <script src="/static/assets/plugins/bootstrap/js/bootstrap.bundle.min.js"></script>
    <!-- Select2 -->
    <script src="/static/assets/plugins/select2/js/select2.full.min.js"></script>
    
    <!-- SweetAlert2 -->
    <script src="/static/assets/plugins/sweetalert2/sweetalert2.min.js"></script>
    
    <!-- AdminLTE -->
    <script src="/static/assets/js/adminlte.js"></script>
    

    视图文件 manager_list.jsp

    视图文件 manager_list.jsp 中在 body 末尾增加消息提示脚本:

    <script>
    $(function() {
        if (${baseResult.status != null && baseResult.status == 200}) {
            const Toast = Swal.mixin({
                toast: true,
                position: 'top',
                showConfirmButton: false,
                timer: 2000,
                timerProgressBar: true
            })
    
            Toast.fire({
                type: 'success',
                title: '${baseResult.message}'
            })
        }
    })
    </script>
    

    4.运行测试

    重启 Tomcat 测试 新增账户 功能,如下为数据验证失败时的提示效果:

    成功添加账户时,会转向列表页,并出现成功提示:

    5.使用表单标签库

    为了简化视图页面的编码,我们可以使用 「Spring MVC - 表单标签库」 章节所讲述的知识重构视图页面。

    引入 form 标签库

    manager_add.jsp 视图页面页头部分引入 form 标签库,代码如下:

    <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
    

    使用表单标签

    改造 form 表单,代码如下:

    <form:form action="/auth/manager/add" method="post" modelAttribute="authManager">
        <div class="card-body">
            <div class="row">
                <div class="col-md-6">
                    <div class="form-group">
                        <label for="userName">用户名</label>
                        <form:input path="userName" cssClass="form-control" placeholder="请输入用户名" />
                    </div>
                    <div class="form-group">
                        <label for="password">密码</label>
                        <form:password path="password" cssClass="form-control" placeholder="请输入密码" />
                    </div>
                    <div class="form-group">
                        <label for="status">状态</label>
                        <form:select path="status" cssClass="form-control select2" style=" 100%;">
                            <option value="0" selected="selected">未激活</option>
                            <option value="1">激活</option>
                            <option value="2">锁定</option>
                            <option value="3">删除</option>
                        </form:select>
                    </div>
                </div>
                <div class="col-md-6">
                    <div class="form-group">
                        <label for="roles">角色</label>
                        <form:select path="roles" cssClass="select2" multiple="multiple" data-placeholder="请选择角色" style=" 100%;">
                            <option value="admin" ${authManager.roles.contains("admin")?"selected":""}>admin</option>
                            <option value="editor" ${authManager.roles.contains("editor")?"selected":""}>editor</option>
                        </form:select>
                    </div>
                    <div class="form-group">
                        <label for="superuser">是否超级用户</label>
                        <form:select path="superuser" cssClass="form-control select2" style=" 100%;">
                            <option value="0" selected="selected">否</option>
                            <option value="1">是</option>
                        </form:select>
                    </div>
                </div>
            </div>
        </div>
        <!-- /.card-body -->
    
        <div class="card-footer">
            <button type="submit" class="btn btn-primary">保存</button>
            <a href="/auth/manager/list" type="button" class="btn btn-default">返回列表</a>
        </div>
    </form:form>
    

    改造后端代码

    改造 ManagerController 控制器中的 GET 方法

    @RequestMapping(value = "add", method = RequestMethod.GET)
    public String add(Model model) {
        AuthManager authManager = new AuthManager();
        model.addAttribute("authManager", authManager);
        return "auth/manager_add";
    }
    

    6.使用表单验证

    引入 jquery-validation

    includes/resources_body.jsp 文件中引入 jquery-validation 插件依赖,代码如下:

    <!-- jquery-validation -->
    <script src="/static/assets/plugins/jquery-validation/jquery.validate.min.js"></script>
    <script src="/static/assets/plugins/jquery-validation/additional-methods.min.js"></script>
    <script src="/static/assets/plugins/jquery-validation/localization/messages_zh.min.js"></script>
    

    定义表单 id

    定义表单的 id ,代码如下:

    <form:form action="/auth/manager/add" id="form" method="post" modelAttribute="authManager">
    

    实现验证脚本

    在视图页 manager_add.jsp 文件中 body 结尾处的脚本内,增加如下代码:

    $("#form").validate({
        rules: {
            userName: {
                required: true,
                minlength: 4,
                maxlength: 20
            },
            password: {
                required: true,
                minlength: 6,
                maxlength: 20
            },
            roles: {
                required: true,
                minlength: 1,
                maxlength: 3
            }
        },
        messages: {
            userName: {
                required: " 请输入用户名",
                minlength: " 用户名不能小于4位",
                maxlength: " 用户名不能大于于20位"
            },
            password: {
                required: " 请输入密码",
                minlength: " 密码不能小于6位",
                maxlength: " 密码不能大于于20位"
            },
            roles: {
                required: " 请选择角色",
                minlength: " 至少选择1个角色",
                maxlength: " 至多选择3个角色"
            }
        },
        errorElement: 'span',
        errorPlacement: function(error, element) {
            error.addClass('invalid-feedback');
            element.closest('.form-group').children('label').append(error);
        },
        highlight: function(element, errorClass, validClass) {
            $(element).addClass('is-invalid');
        },
        unhighlight: function(element, errorClass, validClass) {
            $(element).removeClass('is-invalid');
        }
    });
    

    表单验证效果如下:

    7.实例源码

    实例源码已经托管到如下地址:


    上一篇:账户列表展示

    下一篇:编辑账户


    如果对课程内容感兴趣,可以扫码关注我们的 公众号QQ群,及时关注我们的课程更新

  • 相关阅读:
    CentOS系统下的数据盘挂载
    在iOS微信浏览器中自动播放HTML5 audio(音乐)的2种正确方式
    C盘占用过满问题
    大量ECAgent报错
    微信电脑版不断崩溃
    java web 在tomcat没有正常输出
    文件解压缩失败
    在myeclipse安装beyond插件
    限时免费 GoodSync 10 同步工具【转】
    soapUI的bug切换版本解决
  • 原文地址:https://www.cnblogs.com/liuxiaojun/p/training-monolithic-project-iot-cloud-admin-manager-add.html
Copyright © 2011-2022 走看看