day03【后台】管理员维护

day03【后台】管理员维护

1、分页

1.1、思路

image-20200919184108150

1.2、导入依赖

  • component工程中导入PageHelper的依赖
<!-- MyBatis 分页插件 -->
<dependency>
  <groupId>com.github.pagehelper</groupId>
  <artifactId>pagehelper</artifactId>
</dependency>

1.3、配置 PageHelper

  • Spring的配置文件中,在 SqlSessionFactoryBean 中配置 PageHelper 插件

image-20200611144219761

<!-- 配置 SqlSessionFactoryBean -->
<bean id="sqlSessionFactoryBean"
      class="org.mybatis.spring.SqlSessionFactoryBean">
  <!-- 装配数据源 -->
  <property name="dataSource" ref="dataSource" />
  <!-- 指定 MyBatis 全局配置文件位置 -->
  <property name="configLocation"
            value="classpath:mybatis-config.xml" />
  <!-- 指定 Mapper 配置文件位置 -->
  <property name="mapperLocations"
            value="classpath:mybatis/mapper/*Mapper.xml" />

  <!-- 配置插件 -->
  <property name="plugins">
    <array>
      <!-- 配置PageHelper插件 -->
      <bean class="com.github.pagehelper.PageHelper">
        <property name="properties">
          <props>
            <!-- 配置数据库方言,告诉PageHelper当前使用的数据库 -->
            <prop key="dialect">mysql</prop>
            <!-- 配置页码的合理化修正,在1~总页数之间修正页码 -->
            <prop key="reasonable">true</prop>
          </props>
        </property>
      </bean>
    </array>
  </property>
</bean>

1.4、编写Mapper

  • AdminMapper接口中添加selectAdminByKeyword方法声明,该方法根据关键字搜索用户

image-20200611145258780

List<Admin> selectAdminByKeyword(String keyword);
  • AdminMapper.xml中添加selectAdminByKeyword方法对应的查询SQL语句

image-20200611145813062

<select id="selectAdminByKeyword" resultMap="BaseResultMap">
  select id, login_acct, user_pswd, user_name, email, create_time
  from t_admin
  where
  login_acct like concat("%",#{keyword},"%") or
  user_name like concat("%",#{keyword},"%") or
  email like concat("%",#{keyword},"%")
</select>

1.5、编写Service

  • AdminService.java接口下添加getPageInfo方法,用于查询管理员分页数据

image-20200611150701238

PageInfo<Admin> getPageInfo(String keyword, Integer pageNum, Integer pageSize);
  • AdminServiceImpl.java中实现上述方法

image-20200611150826737

@Override
public PageInfo<Admin> getPageInfo(String keyword, Integer pageNum, Integer pageSize) {		
  // 1.调用PageHelper的静态方法开启分页功能
  // 这里充分体现了PageHelper的“非侵入式”设计:原本要做的查询不必有任何修改
  PageHelper.startPage(pageNum, pageSize);

  // 2.执行查询
  List<Admin> list = adminMapper.selectAdminByKeyword(keyword);

  // 3.封装到PageInfo对象中
  return new PageInfo<>(list);
}

1.6、编写Handler

  • AdminHandler调用AdminService获取数据

image-20200611151604944

@RequestMapping("/admin/get/page.html")
public String getPageInfo(			
  // 使用@RequestParam注解的defaultValue属性,指定默认值,在请求中没有携带对应参数时使用默认值
  // keyword默认值使用空字符串,和SQL语句配合实现两种情况适配
  @RequestParam(value="keyword", defaultValue="") String keyword,

  // pageNum默认值使用1
  @RequestParam(value="pageNum", defaultValue="1") Integer pageNum,

  // pageSize默认值使用5
  @RequestParam(value="pageSize", defaultValue="5") Integer pageSize,

  ModelMap modelMap			
) {		
  // 调用Service方法获取PageInfo对象
  PageInfo<Admin> pageInfo = adminService.getPageInfo(keyword, pageNum, pageSize);

  // 将PageInfo对象存入模型
  modelMap.addAttribute(CrowdConstant.ATTR_NAME_PAGE_INFO, pageInfo);

  return "admin-page";
}

1.7、编写页面

  • component工程的pom文件中引入JSTL标签库依赖

image-20200611152912242

<!-- JSTL标签库 -->
<dependency>
  <groupId>jstl</groupId>
  <artifactId>jstl</artifactId>
</dependency>
  • include-sidebar.jsp页面中添加跳转地址

image-20200611153454410

<li style="height: 30px;"><a href="admin/get/page.html"><i
							class="glyphicon glyphicon-user"></i> 用户维护</a></li>
  • admin-page.jsp页面中取出数据并显示

image-20200611153605288

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html lang="zh-CN">
<%@include file="/WEB-INF/include-head.jsp"%>

<body>
	<%@ include file="/WEB-INF/include-nav.jsp"%>
	<div class="container-fluid">
		<div class="row">
			<%@ include file="/WEB-INF/include-sidebar.jsp"%>
			<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
				<div class="panel panel-default">
					<div class="panel-heading">
						<h3 class="panel-title">
							<i class="glyphicon glyphicon-th"></i> 数据列表
						</h3>
					</div>
					<div class="panel-body">
						<form class="form-inline" role="form" style="float: left;">
							<div class="form-group has-feedback">
								<div class="input-group">
									<div class="input-group-addon">查询条件</div>
									<input class="form-control has-success" type="text"
										placeholder="请输入查询条件">
								</div>
							</div>
							<button type="button" class="btn btn-warning">
								<i class="glyphicon glyphicon-search"></i> 查询
							</button>
						</form>
						<button type="button" class="btn btn-danger"
							style="float: right; margin-left: 10px;">
							<i class=" glyphicon glyphicon-remove"></i> 删除
						</button>
						<button type="button" class="btn btn-primary"
							style="float: right;" onclick="window.location.href='add.html'">
							<i class="glyphicon glyphicon-plus"></i> 新增
						</button>
						<br>
						<hr style="clear: both;">
						<div class="table-responsive">
							<table class="table  table-bordered">
								<thead>
									<tr>
										<th width="30">#</th>
										<th width="30"><input type="checkbox"></th>
										<th>账号</th>
										<th>名称</th>
										<th>邮箱地址</th>
										<th width="100">操作</th>
									</tr>
								</thead>
								<tbody>
									<c:if test="${empty requestScope.pageInfo.list }">
										<tr>
											<td colspan="6" align="center">抱歉!没有查询到您要的数据!</td>
										</tr>
									</c:if>
									<c:if test="${!empty requestScope.pageInfo.list }">
										<c:forEach items="${requestScope.pageInfo.list }" var="admin"
											varStatus="myStatus">
											<tr>
												<td>${myStatus.count }</td>
												<td><input type="checkbox"></td>
												<td>${admin.loginAcct }</td>
												<td>${admin.userName }</td>
												<td>${admin.email }</td>
												<td>
													<button type="button" class="btn btn-success btn-xs">
														<i class=" glyphicon glyphicon-check"></i>
													</button>
													<button type="button" class="btn btn-primary btn-xs">
														<i class=" glyphicon glyphicon-pencil"></i>
													</button>
													<button type="button" class="btn btn-danger btn-xs">
														<i class=" glyphicon glyphicon-remove"></i>
													</button>
												</td>
											</tr>
										</c:forEach>
									</c:if>
								</tbody>
								<tfoot>
									<tr>
										<td colspan="6" align="center">
											<ul class="pagination">
												<li class="disabled"><a href="#">上一页</a></li>
												<li class="active"><a href="#">1 <span
														class="sr-only">(current)</span></a></li>
												<li><a href="#">2</a></li>
												<li><a href="#">3</a></li>
												<li><a href="#">4</a></li>
												<li><a href="#">5</a></li>
												<li><a href="#">下一页</a></li>
											</ul>
										</td>
									</tr>
								</tfoot>
							</table>
						</div>
					</div>
				</div>
			</div>
		</div>
	</div>
</body>
</html>

1.8、测试

  • 测试成功

image-20200611154114134

1.9、Tips

  • 以上部分均为day02内容,以下部分才是day03内容

2、分页导航条

2.1、导入资源

  • webapp目录下引入Pagination所需要的jscss

image-20200611161028488

2.2、在需要的页面引入资源

  • admin-page.jsp页面引入相关的资源,由于<%@include%>引入了jQuery,将资源的引入jQuery的后面

image-20200611161624583

<%@include file="/WEB-INF/include-head.jsp"%>
<link rel="stylesheet" href="css/pagination.css" />
<script type="text/javascript" src="jquery/jquery.pagination.js"></script>

2.3、加入分页条

  • 加入Pagination:一个div即可

image-20200611161839286

<tfoot>
  <tr>
    <td colspan="6" align="center">
      <div id="Pagination" class="pagination">
        <!-- 这里显示分页 -->
      </div>
    </td>
  </tr>
</tfoot>

2.4、使用Pagination

  • admin-page.jsp页面下添加如下代码,使用Pagination生成分页条

image-20200611164803787

<script type="text/javascript">	
	$(function(){	
		// 调用后面声明的函数对页码导航条进行初始化操作
		initPagination();	
	});
	
	// 生成页码导航条的函数
	function initPagination() {		
		// 获取总记录数
		var totalRecord = ${requestScope.pageInfo.total};
		
		// 声明一个JSON对象存储Pagination要设置的属性
		var properties = {
			num_edge_entries: 3,								// 边缘页数
			num_display_entries: 5,								// 主体页数
			callback: pageSelectCallback,						// 指定用户点击“翻页”的按钮时跳转页面的回调函数
			items_per_page: ${requestScope.pageInfo.pageSize},	// 每页要显示的数据的数量
			current_page: ${requestScope.pageInfo.pageNum - 1},	// Pagination内部使用pageIndex来管理页码,pageIndex从0开始,pageNum从1开始,所以要减一
			prev_text: "上一页",									// 上一页按钮上显示的文本
			next_text: "下一页"									// 下一页按钮上显示的文本
		};
		
		// 生成页码导航条
		$("#Pagination").pagination(totalRecord, properties);		
	}
	
	// 回调函数的含义:声明出来以后不是自己调用,而是交给系统或框架调用
	// 用户点击“上一页、下一页、1、2、3……”这样的页码时调用这个函数实现页面跳转
	// pageIndex是Pagination传给我们的那个“从0开始”的页码
	function pageSelectCallback(pageIndex, jQuery) {		
		// 根据pageIndex计算得到pageNum
		var pageNum = pageIndex + 1;
		
		// 跳转页面
		window.location.href = "admin/get/page.html?pageNum="+pageNum;
		
		// 由于每一个页码按钮都是超链接,所以在这个函数最后取消超链接的默认行为
		return false;
	}	
</script>

2.5、修复Pagination Bug

  • Bug产生原因:请求页面 --> 绘制分页条 --> 调用回调函数 --> 页面跳转 --> 请求页面 --> 绘制分页条 --> 调用回调函数 --> 页面跳转 … 就这样陷入了陷入死循环

image-20200611165810832

2.6、测试

  • 成了~

image-20200611165612747

3、关键词查询

3.1、修改表单

  • 修改admin-page.jsp中查询表单
    • 表单提交URIadmin/get/page.html
    • <input name="keyword"/>:输入框名称需要与Handler参数名称对应
    • <button type="submit">submit按钮用于提交表单
<form action="admin/get/page.html" class="form-inline" role="form"
      style="float: left;">
  <div class="form-group has-feedback">
    <div class="input-group">
      <div class="input-group-addon">查询条件</div>
      <input name="keyword" class="form-control has-success"
             type="text" placeholder="请输入查询条件" value="${param.keyword }">
    </div>
  </div>
  <button type="submit" class="btn btn-warning">
    <i class="glyphicon glyphicon-search"></i> 查询
  </button>
</form>

3.2、翻页带上关键词查询条件

  • 由于搜索关键词之后,并没有进行重定向操作,所以都是同一次请求,直接从请求参数中取出搜索关键词即可

image-20200611192707341

<script type="text/javascript">	
	$(function(){	
		// 调用后面声明的函数对页码导航条进行初始化操作
		initPagination();	
	});
	
	// 生成页码导航条的函数
	function initPagination() {		
		// 获取总记录数
		var totalRecord = ${requestScope.pageInfo.total};
		
		// 声明一个JSON对象存储Pagination要设置的属性
		var properties = {
			num_edge_entries: 3,								// 边缘页数
			num_display_entries: 5,								// 主体页数
			callback: pageSelectCallback,						// 指定用户点击“翻页”的按钮时跳转页面的回调函数
			items_per_page: ${requestScope.pageInfo.pageSize},	// 每页要显示的数据的数量
			current_page: ${requestScope.pageInfo.pageNum - 1},	// Pagination内部使用pageIndex来管理页码,pageIndex从0开始,pageNum从1开始,所以要减一
			prev_text: "上一页",									// 上一页按钮上显示的文本
			next_text: "下一页"									// 下一页按钮上显示的文本
		};
		
		// 生成页码导航条
		$("#Pagination").pagination(totalRecord, properties);	
	}
	
	// 回调函数的含义:声明出来以后不是自己调用,而是交给系统或框架调用
	// 用户点击“上一页、下一页、1、2、3……”这样的页码时调用这个函数实现页面跳转
	// pageIndex是Pagination传给我们的那个“从0开始”的页码
	function pageSelectCallback(pageIndex, jQuery) {
		
		// 根据pageIndex计算得到pageNum
		var pageNum = pageIndex + 1;
		
		// 跳转页面
		window.location.href = "admin/get/page.html?pageNum="+pageNum+"&keyword=${param.keyword}";
		
		// 由于每一个页码按钮都是超链接,所以在这个函数最后取消超链接的默认行为
		return false;
	}	
</script>

3.3、测试

  • 乌拉~

image-20200611192206287

4、单条删除

4.1、提交删除请求

  • admin-page.jsp页面,添加提交删除请求的a标签,删除管理员时,除了要携带管理员Idid,还需要附带当前页码:pageNum,当前查询关键词:keyword

image-20200611212429605

<a href="admin/remove/${admin.id }/${requestScope.pageInfo.pageNum }/${param.keyword }.html"
		class="btn btn-danger btn-xs">
		<i class=" glyphicon glyphicon-remove"></i></a>

4.2、编写业务逻辑

4.2.1、Handler代码
  • AdminHandler中添加remove方法,从路径变量中取出所需的参数即可

image-20200611212549366

@RequestMapping("/admin/remove/{adminId}/{pageNum}/{keyword}.html")
public String remove(
  @PathVariable("adminId") Integer adminId,
  @PathVariable("pageNum") Integer pageNum,
  @PathVariable("keyword") String keyword
) {		
  // 执行删除
  adminService.remove(adminId);

  // 页面跳转:回到分页页面		
  // 尝试方案1:直接转发到admin-page.jsp会无法显示分页数据
  // return "admin-page";

  // 尝试方案2:转发到/admin/get/page.html地址,一旦刷新页面会重复执行删除浪费性能
  // return "forward:/admin/get/page.html";

  // 尝试方案3:重定向到/admin/get/page.html地址
  // 同时为了保持原本所在的页面和查询关键词再附加pageNum和keyword两个请求参数
  return "redirect:/admin/get/page.html?pageNum="+pageNum+"&keyword="+keyword;
}
4.2.2、Service代码
  • Service接口中声明remove方法,在Service实现类中实现remove方法

image-20200611212704950

@Override
public void remove(Integer adminId) {
  adminMapper.deleteByPrimaryKey(adminId);	
}

4.3、莫名其妙的Bug

4.3.1、Bug描述
  • 莫名其妙会执行删除管理员的操作,但是我并没有执行删除操作。。。
4.3.2、Bug排除
  • 特么居然是因为FasterChrome插件,只要你鼠标悬停有超链接的标签上,这个插件会预先发送请求给服务器,并接受服务器的请求,以缓存方式保存,等到你点击时,便会直接从缓存中取出数据,让你纵享丝滑~~~

image-20200619104904312

  • 恰好删除按钮并没有写JS代码,只要鼠标悬停在删除按钮上,便会触发删除请求,我特么的,终于知道为什么t_admin表中的数据莫名其妙地消失了。。。

image-20200619105637979

  • 程序在断点处停住。。。

image-20200619105642629

4.3.3、解决办法
  • FasterChrome插件禁用掉

image-20200619105807912

5、新增

5.1、思路

image-20200919184738292

5.2、设置唯一约束

  • login_acct字段设置为唯一约束

image-20200611213658473

  • 查看历史记录得到设置唯一约束的SQL语句

image-20200611213821803

ALTER TABLE `project_crowd`.`t_admin` ADD UNIQUE INDEX (`login_acct`); 

5.3、提交新增请求

  • 修改admin-page.jsp页面,添加提交新增请求的a标签

image-20200611220431380

<a style="float: right;" href="admin/to/add/page.html"
   class="btn btn-primary">
   <i class="glyphicon glyphicon-plus"></i>新增</a> 

5.4、配置view-controller

  • 由于点击a标签超链接后直接转发页面,无需其他操作,所以我们直接配置view-controller

image-20200611220646143

<mvc:view-controller 
	path="/admin/to/add/page.html" view-name="admin-add"/>

5.5、准备表单页面

  • 准备新增管理员表单页面admin-add.jsp
    • 表单提交地址为admin/save.html
    • 各个input标签的name属性值需要与java bean属性对应

image-20200611220729015

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="zh-CN">
<%@include file="/WEB-INF/include-head.jsp"%>

<body>
	<%@ include file="/WEB-INF/include-nav.jsp"%>
	<div class="container-fluid">
		<div class="row">
			<%@ include file="/WEB-INF/include-sidebar.jsp"%>
			<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
				<ol class="breadcrumb">
					<li><a href="/admin/to/main/page.html">首页</a></li>
					<li><a href="/admin/get/page.html">数据列表</a></li>
					<li class="active">新增</li>
				</ol>
				<div class="panel panel-default">
					<div class="panel-heading">
						表单数据
						<div style="float: right; cursor: pointer;" data-toggle="modal"
							data-target="#myModal">
							<i class="glyphicon glyphicon-question-sign"></i>
						</div>
					</div>
					<div class="panel-body">
						<form action="admin/save.html" method="post" role="form">
							<p>${requestScope.exception.message }</p>
							<div class="form-group">
								<label for="exampleInputPassword1">登录账号</label> 
								<input
									name="loginAcct" type="text" class="form-control"
									id="exampleInputPassword1" placeholder="请输入登录账号">
							</div>
							<div class="form-group">
								<label for="exampleInputPassword1">登录密码</label> 
								<input
									name="userPswd" type="text" class="form-control"
									id="exampleInputPassword1" placeholder="请输入登录密码">
							</div>
							<div class="form-group">
								<label for="exampleInputPassword1">用户昵称</label> 
								<input
									name="userName" type="text" class="form-control"
									id="exampleInputPassword1" placeholder="请输入用户名称">
							</div>
							<div class="form-group">
								<label for="exampleInputEmail1">邮箱地址</label> 
								<input type="email"
									name="email" class="form-control" id="exampleInputEmail1"
									placeholder="请输入邮箱地址">
								<p class="help-block label label-warning">请输入合法的邮箱地址, 格式为:
									xxxx@xxxx.com</p>
							</div>
							<button type="submit" class="btn btn-success">
								<i class="glyphicon glyphicon-plus"></i> 新增
							</button>
							<button type="reset" class="btn btn-danger">
								<i class="glyphicon glyphicon-refresh"></i> 重置
							</button>
						</form>
					</div>
				</div>
			</div>
		</div>
	</div>
</body>
</html>

5.6、Handler代码

  • Handler中保存新增的管理员之后,重定向至分页页面

image-20200611221454231

@RequestMapping("/admin/save.html")
public String save(Admin admin) {		
  adminService.saveAdmin(admin);	
  return "redirect:/admin/get/page.html?pageNum="+Integer.MAX_VALUE;
}

5.7、用户名重复异常

  • util工程下创建LoginAcctAlreadyInUseException类,表示用户名重复异常

image-20200611221549401

/**
 * 保存或更新Admin时如果检测到登录账号重复抛出这个异常
 * @author Lenovo
 *
 */
public class LoginAcctAlreadyInUseException extends RuntimeException {

	private static final long serialVersionUID = 1L;

	public LoginAcctAlreadyInUseException() {
		super();
	}

	public LoginAcctAlreadyInUseException(String message, Throwable cause, boolean enableSuppression,
			boolean writableStackTrace) {
		super(message, cause, enableSuppression, writableStackTrace);
	}

	public LoginAcctAlreadyInUseException(String message, Throwable cause) {
		super(message, cause);
	}

	public LoginAcctAlreadyInUseException(String message) {
		super(message);
	}

	public LoginAcctAlreadyInUseException(Throwable cause) {
		super(cause);
	}

}

5.8、Service代码

  • Service中实现上述Handler中调用的方法
    • 将管理员密码加密存储
    • 设置管理员创建时间
    • 如果login_acct键重复,则抛出异常

image-20200611221703001

private Logger logger = LoggerFactory.getLogger(AdminServiceImpl.class);

@Override
public void saveAdmin(Admin admin) {	
  // 1.密码加密
  String userPswd = admin.getUserPswd();
  userPswd = CrowdUtil.md5(userPswd);
  admin.setUserPswd(userPswd);

  // 2.生成创建时间
  Date date = new Date();
  SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  String createTime = format.format(date);
  admin.setCreateTime(createTime);

  // 3.执行保存
  try {
    adminMapper.insert(admin);
  } catch (Exception e) {
    e.printStackTrace();			
    logger.info("异常全类名="+e.getClass().getName());			
    if(e instanceof DuplicateKeyException) {
      throw new LoginAcctAlreadyInUseException(CrowdConstant.MESSAGE_LOGIN_ACCT_ALREADY_IN_USE);
    }
  }		
}

5.9、统一处理异常

  • CrowdExceptionResolver配置类中统一处理LoginAcctAlreadyInUseException类型的异常

image-20200611221926174

@ExceptionHandler(value = LoginAcctAlreadyInUseException.class)
public ModelAndView resolveLoginAcctAlreadyInUseException(
  LoginAcctAlreadyInUseException exception,
  HttpServletRequest request,
  HttpServletResponse response
) throws IOException {	
  String viewName = "admin-add";		
  return commonResolve(viewName, exception, request, response);
}

// @ExceptionHandler将一个具体的异常类型和一个方法关联起来
private ModelAndView commonResolve(
  // 异常处理完成后要去的页面
  String viewName,
  // 实际捕获到的异常类型
  Exception exception,
  // 当前请求对象
  HttpServletRequest request,
  // 当前响应对象
  HttpServletResponse response
) throws IOException {
  // 1.判断当前请求类型
  boolean judgeResult = CrowdUtil.judgeRequestType(request);
  // 2.如果是Ajax请求
  if (judgeResult) {
    // 3.创建ResultEntity对象
    ResultEntity<Object> resultEntity = ResultEntity.failed(exception.getMessage());
    // 4.创建Gson对象
    Gson gson = new Gson();
    // 5.将ResultEntity对象转换为JSON字符串
    String json = gson.toJson(resultEntity);
    // 6.将JSON字符串作为响应体返回给浏览器
    response.getWriter().write(json);
    // 7.由于上面已经通过原生的response对象返回了响应,所以不提供ModelAndView对象
    return null;
  }
  // 8.如果不是Ajax请求则创建ModelAndView对象
  ModelAndView modelAndView = new ModelAndView();
  // 9.将Exception对象存入模型
  modelAndView.addObject("exception", exception);
  // 10.设置对应的视图名称
  modelAndView.setViewName(viewName);
  // 11.返回modelAndView对象
  return modelAndView;
}

5.10、测试

  • 添加成功

image-20200611222407258

  • 添加失败

image-20200611222330699

6、更新

6.1、思路

image-20200919184902637

6.2、提交更新请求

  • 修改admin-page.jsp页面,添加提交更新请求的a标签
    • 更新管理员信息需要管理员Id
    • 更新完成后回到分页页面需要:当前页面pageNum和搜索关键词keyword

image-20200612101421105

<a href="admin/to/edit/page.html?adminId=${admin.id }&pageNum=${requestScope.pageInfo.pageNum }&keyword=${param.keyword }"
   class="btn btn-primary btn-xs">
   <i	class=" glyphicon glyphicon-pencil"></i></a> 

6.3、查询管理员

6.3.1、Handler代码
  • AdminHandler中查询出Admin信息,并转发至admin-edit.jsp页面;由于是同一次请求,所以请求参数pageNumkeyword到更新Admin的时候再取出来使用

image-20200612101744867

@RequestMapping("/admin/to/edit/page.html")
public String toEditPage(
  @RequestParam("adminId") Integer adminId,
  ModelMap modelMap
) {		
  // 1.根据adminId查询Admin对象
  Admin admin = adminService.getAdminById(adminId);

  // 2.将Admin对象存入模型
  modelMap.addAttribute("admin", admin);

  return "admin-edit";
}
6.3.2、Service代码
  • Service中实现上述Handler中调用的方法

image-20200612102330407

@Override
public Admin getAdminById(Integer adminId) {
  return adminMapper.selectByPrimaryKey(adminId);
}

6.4、表单回显

  • 添加admin-edit.jsp页面,用于表单回显,表单提交地址为admin/update.html

image-20200612102437433

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="zh-CN">
<%@include file="/WEB-INF/include-head.jsp"%>

<body>
	<%@ include file="/WEB-INF/include-nav.jsp"%>
	<div class="container-fluid">
		<div class="row">
			<%@ include file="/WEB-INF/include-sidebar.jsp"%>
			<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
				<ol class="breadcrumb">
					<li><a href="/admin/to/main/page.html">首页</a></li>
					<li><a href="/admin/get/page.html">数据列表</a></li>
					<li class="active">更新</li>
				</ol>
				<div class="panel panel-default">
					<div class="panel-heading">
						表单数据
						<div style="float: right; cursor: pointer;" data-toggle="modal"
							data-target="#myModal">
							<i class="glyphicon glyphicon-question-sign"></i>
						</div>
					</div>
					<div class="panel-body">
						<form action="admin/update.html" method="post" role="form">
							<input type="hidden" name="id" value="${requestScope.admin.id }" />
							<input type="hidden" name="pageNum" value="${param.pageNum }" />
							<input type="hidden" name="keyword" value="${param.keyword }" />
							<p>${requestScope.exception.message }</p>
							<div class="form-group">
								<label for="exampleInputPassword1">登录账号</label>
								<input
									name="loginAcct" 
									value="${requestScope.admin.loginAcct }"
									type="text" class="form-control"
									id="exampleInputPassword1" placeholder="请输入登录账号">
							</div>
							<div class="form-group">
								<label for="exampleInputPassword1">用户昵称</label>
								<input
									name="userName"
									value="${requestScope.admin.userName }" 
									type="text" class="form-control"
									id="exampleInputPassword1" placeholder="请输入用户名称">
							</div>
							<div class="form-group">
								<label for="exampleInputEmail1">邮箱地址</label>
								<input type="email"
									name="email" 
									value="${requestScope.admin.email }" class="form-control" id="exampleInputEmail1"
									placeholder="请输入邮箱地址">
								<p class="help-block label label-warning">请输入合法的邮箱地址, 格式为:
									xxxx@xxxx.com</p>
							</div>
							<button type="submit" class="btn btn-success">
								<i class="glyphicon glyphicon-edit"></i> 更新
							</button>
							<button type="reset" class="btn btn-danger">
								<i class="glyphicon glyphicon-refresh"></i> 重置
							</button>
						</form>
					</div>
				</div>
			</div>
		</div>
	</div>
</body>
</html>

6.5、Handler代码:更新管理员

6.5.1、Handler代码
  • AdminHandler中更新Admin管理员的信息,并重定向至分页页面

image-20200612101744867

@RequestMapping("/admin/update.html")
public String update(Admin admin, @RequestParam("pageNum") Integer pageNum, @RequestParam("keyword") String keyword) {		
  adminService.update(admin);		
  return "redirect:/admin/get/page.html?pageNum="+pageNum+"&keyword="+keyword;
}
6.5.2、Service代码
  • Service中保存Admin信息,并且捕获唯一键约束异常

image-20200612102330407

@Override
public void update(Admin admin) {	
  // “Selective”表示有选择的更新,对于null值的字段不更新
  try {
    adminMapper.updateByPrimaryKeySelective(admin);
  } catch (Exception e) {
    e.printStackTrace();			
    logger.info("异常全类名="+e.getClass().getName());		
    if(e instanceof DuplicateKeyException) {
      throw new LoginAcctAlreadyInUseForUpdateException(CrowdConstant.MESSAGE_LOGIN_ACCT_ALREADY_IN_USE);
    }
  }
}

6.6、异常处理

6.6.1、创建异常类
  • util工程添加LoginAcctAlreadyInUseForUpdateException类,该类表示更新Admin时,其login_acct字段不唯一,引发的异常

image-20200612103500808

/**
 * 保存或更新Admin时如果检测到登录账号重复抛出这个异常
 * @author Lenovo
 *
 */
public class LoginAcctAlreadyInUseForUpdateException extends RuntimeException {

	private static final long serialVersionUID = 1L;

	public LoginAcctAlreadyInUseForUpdateException() {
		super();
	}

	public LoginAcctAlreadyInUseForUpdateException(String message, Throwable cause, boolean enableSuppression,
			boolean writableStackTrace) {
		super(message, cause, enableSuppression, writableStackTrace);
	}

	public LoginAcctAlreadyInUseForUpdateException(String message, Throwable cause) {
		super(message, cause);
	}

	public LoginAcctAlreadyInUseForUpdateException(String message) {
		super(message);
	}

	public LoginAcctAlreadyInUseForUpdateException(Throwable cause) {
		super(cause);
	}

}
6.6.2、处理异常
  • CrowdExceptionResolver配置类中统一处理LoginAcctAlreadyInUseForUpdateException类型的异常

image-20200612103903537

@ExceptionHandler(value = LoginAcctAlreadyInUseForUpdateException.class)
public ModelAndView resolveLoginAcctAlreadyInUseForUpdateException(
  LoginAcctAlreadyInUseForUpdateException exception,
  HttpServletRequest request,
  HttpServletResponse response
) throws IOException {	
  String viewName = "system-error";	
  return commonResolve(viewName, exception, request, response);
}

6.7、测试

  • 更新成功

image-20200612104317328

  • 更新失败

image-20200612104501829

7、Ajax加餐

7.1、异步Ajax

  • 添加test.jsp页面用于测试Ajax请求

image-20200612150519969

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="zh-CN">
<%@include file="/WEB-INF/include-head.jsp"%>
<script type="text/javascript">
	$(function() {
		$("#asyncBtn").click(function() {
			console.log("ajax函数之前");
      $.ajax({
          "url" : "test/ajax/async.html",
          "type" : "post",
          "dataType" : "text",
          "async" : true, // 默认值
          "success" : function(response) {
            // success是接收到服务器端响应后执行
            console.log("ajax函数内部的success函数" + response);
          }
        });

			// 在$.ajax()执行完成后执行,不等待success()函数
			console.log("ajax函数之后");

			/* 等待5s后,再执行function()定义的函数
			setTimeout(function(){
				console.log("ajax函数之后");
			}, 5000); */
		});
	});
</script>
<body>
	<%@ include file="/WEB-INF/include-nav.jsp"%>
	<div class="container-fluid">
		<div class="row">
			<%@ include file="/WEB-INF/include-sidebar.jsp"%>
			<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
				<button id="asyncBtn">发送Ajax请求</button>
			</div>
		</div>
	</div>
</body>
</html>
  • Handler代码

image-20200612150649060

@ResponseBody
@RequestMapping("/test/ajax/async.html")
public String testAsync() throws InterruptedException {
	Thread.sleep(5000);
	return "success";
}
  • 测试结果:

image-20200612151018040

image-20200612150158032

7.2、同步Ajax

  • Ajax请求修改为同步:"async" : false
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="zh-CN">
<%@include file="/WEB-INF/include-head.jsp"%>
<script type="text/javascript">
	$(function() {
		$("#asyncBtn").click(function() {
			console.log("ajax函数之前");
      
			$.ajax({
				"url" : "test/ajax/async.html",
				"type" : "post",
				"dataType" : "text",
				"async" : false, // 关闭异步工作模型,使用同步方式工作。此时:所有操作在同一个线程内按顺序完成
				"success" : function(response) {
					// success是接收到服务器端响应后执行
					console.log("ajax函数内部的success函数" + response);
				}
			});

			// 在$.ajax()执行完成后执行,不等待success()函数
			console.log("ajax函数之后");
			/* setTimeout(function(){
				
			}, 5000); */
		});
	});
</script>
<body>
	<%@ include file="/WEB-INF/include-nav.jsp"%>
	<div class="container-fluid">
		<div class="row">
			<%@ include file="/WEB-INF/include-sidebar.jsp"%>
			<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
				<button id="asyncBtn">发送Ajax请求</button>
			</div>
		</div>
	</div>
</body>
</html>
  • Handler代码不变,测试结果如下

image-20200612151419394

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值