Original Address: http://www.work100.net/training/monolithic-project-iot-cloud-admin-manager-add.html
More Tutorials: beam cloud - free course
New Account
No. | Article section | video |
---|---|---|
1 | Outline | - |
2 | The back-end code implementation | - |
3 | Achieve front page | - |
4 | Testing and certification | - |
5 | Use the form tag library | - |
6 | Use Form Validation | - |
7 | Source code examples | - |
Please refer above 章节导航
to read
1 Overview
This section realization 新增账户
function, page effect is as follows:
2. The back-end code implementation
To reduce the coupling, we suggest that you 新增
, 编辑
, 查看
function encoded separately, not mixed in one method.
We now demonstrate the function is relatively simple, but the real business function will become very complicated, if the code is mixed together, then the code complexity will grow exponentially.
Next, we gradually reconstructed ManagerController
class.
GET method
@RequestMapping(value = "add", method = RequestMethod.GET)
public String add() {
return "auth/manager_add";
}
POST method
@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";
}
}
Description :
-
Backend must submit data to verify the legitimacy of the front end, in order to ensure data security
-
The method used
BaseResult
andHttpUtils
two classes, the following were introduced
BaseResult class
In order to more convenient operation result is transmitted to the front page, we introduce a generic BaseResult
class, as follows:
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;
}
}
Class file location
iot-cloud-commons
in the projectnet.work100.training.stage2.iot.cloud.commons.dto
under the class package.
HttpUtils class
To BaseResult
return a status code configured generic class HttpUtils
, as follows:
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;
}
Class file location
iot-cloud-commons
in the projectnet.work100.training.stage2.iot.cloud.commons.utils
under the class package.
AuthManagerService service interface
Reconstruction of AuthManagerService
the service interface insert
as the following code:
/**
* 新增
*
* @param authManager
* @return
*/
BaseResult insert(AuthManager authManager);
AuthManagerServiceImpl service implementation
Reconstruction of AuthManagerServiceImpl
service implementation insert
method, the code is as follows:
@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("未知错误");
}
}
New generateUserKey
methods to achieve userKey
generation logic, as follows:
/**
* 生成 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. achieve front page
View file manager_add.jsp
In views/auth/
adding a directory manager_add.jsp
view file, code is as follows:
<%@ 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="width: 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="width: 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="width: 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>
Dependence script and controls
End of the file we added a paragraph JS
script:
The following code is to allow select
control application Bootstrap4
styles:
//Initialize Select2 Elements
$('.select2').select2();
//Initialize Select2 Elements
$('.select2bs4').select2({
theme: 'bootstrap4'
});
The following code is an operation result to the message out to show more friendly to the user:
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}'
})
}
Page used in select
controls and prompts 消息
depend on the relevant plug-in, which relies plug CSS
and JS
are in resources_head.js
and resources_body.js
the introduction of:
resources_head.js
code show as below:
<%@ 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
code show as below:
<%@ 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>
View file manager_list.jsp
View files manager_list.jsp
in the body
add message prompt end of the script:
<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. Run the test
Restart Tomcat
test 新增账户
function, the following data validation prompt effect at the time of failure:
When successfully added an account, the list will turn the page and success prompted:
5. Use form tag library
In order to simplify the coding view of the page, we can use the " Spring MVC - form tag library " section of the knowledge about the reconstruction of page views.
The introduction of form tag library
In the manager_add.jsp
introduction section view page header form
tag library, as follows:
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
Use the form tag
The transformation of form
the form, as follows:
<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="width: 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="width: 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="width: 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>
Transformation back-end code
Reconstruction ManagerController
controller GET
method
@RequestMapping(value = "add", method = RequestMethod.GET)
public String add(Model model) {
AuthManager authManager = new AuthManager();
model.addAttribute("authManager", authManager);
return "auth/manager_add";
}
6. Use Form Validation
Introducing jquery-validation
In includes/resources_body.jsp
introducing the document jquery-validation
plug-dependent code is as follows:
<!-- 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>
Custom Form id
Defined form id
, as follows:
<form:form action="/auth/manager/add" id="form" method="post" modelAttribute="authManager">
Achieve validation script
In view page manager_add.jsp
file body
within the script at the end, add the following code:
$("#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');
}
});
Form validation results are as follows:
Example 7. Source
Examples of the source has been managed to the following address:
-
https://github.com/work100-net/training-stage2/tree/master/iot-cloud3
-
https://gitee.com/work100-net/training-stage2/tree/master/iot-cloud3
Previous: Accounts list shows
Next: Edit Account
If you are interested in course content, our attention can sweep the yard
公众号
orQQ群
in a timely manner to our curriculum update