由于尚硅谷的视频是通过Eclipse软件来做的,其中有些操作与IDEA上有所区别,所以我在这里将IDEA区别于Eclipse的操作、操作过程中涉及的源码(与视频的源码略有出入)以及大家可能遇到的种种问题分享给大家,这些源码在我这里均是通过测试的,仅供参考!
1 分页——用户维护
1.1 mybatis配置插件
修改webui\src\main\resources\spring-persist-mybatis.xml
按照工程文件的props标签写入会报错,参考网友的改为了value标签
<!--配置插件-->
<property name="plugins">
<array>
<bean class="com.github.pagehelper.PageInterceptor">
<property name="properties">
<value>
<!--配置数据库方言,告诉PageHelper-->
helperDialect=mysql
<!-- 配置页码的合理化修正,在1~ 总页数之间修正页码-->
reasonable=true
</value>
</property>
</bean>
</array>
</property>
1.2 AdminMapper
修改webui\src\main\resources\mybatis\mapper\AdminMapper.xml
<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>
修改component\src\main\java\com\atguigu\crowd\mapper\AdminMapper.java
List<Admin> selectAdminByKeyword(String keyword);
1.3 AdminService
修改component\src\main\java\com\atguigu\crowd\service\api\AdminService.java
PageInfo<Admin> getPageInfo(String keyword, Integer pageNum, Integer pageSize);
修改component\src\main\java\com\atguigu\crowd\service\impl\AdminServiceImpl.java
@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.4 AdminHandler
修改component\src\main\java\com\atguigu\crowd\mvc\handler\AdminHandler.java
@RequestMapping(value = "/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";
}
修改util\src\main\java\com\atguigu\crowd\constant\CrowdConstant.java
public static final String ATTR_NAME_PAGE_INFO = "pageInfo";
1.5 admin-page页面
在webui\src\main\webapp\WEB-INF新建admin-page.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html lang="zh-CN">
<%@include file="include-head.jsp" %>
<body>
<%@include file="include-nav.jsp" %>
<div class="container-fluid">
<div class="row">
<%@include file="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;" οnclick="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>
如果发现taglib指令找不到标签库(标红),优先检查是否添加了如下两个依赖:
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
修改webui\src\main\webapp\WEB-INF\include-sidebar.jsp 用户维护界面为正确路径
<li style="height:30px;">
<a href="admin/get/page.html"><i class="glyphicon glyphicon-user"></i> 用户维护</a>
</li>
测试如下:点击用户维护,出现账号信息
2 分页导航条
2.1 第三方库
将pagination.css放至webui\src\main\webapp\css中
将jquery.pagination.js放至webui\src\main\webapp\jquery中
2.2 admin-page
修改webui\src\main\webapp\WEB-INF\admin-page.jsp
在head引入部分下方引入:
<%@include file="/WEB-INF/include-head.jsp" %>
<link rel="stylesheet" href="css/pagination.css">
<script type="text/javascript" src="jquery/jquery.pagination.js"></script>
在tfoot部分修改:
<tfoot>
<tr>
<td colspan="6" align="center">
<div id="Pagination" class="pagination"><!-- 这里显示分页 --></div>
</td>
</tr>
</tfoot>
新增js函数:
<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来管理页码,从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.3 修改库文件bug
修改webui\src\main\webapp\jquery\jquery.pagination.js
// 将最后的回调函数注释掉以免死循环
// 回调函数
// opts.callback(current_page, this);
2.4 测试
测试,实现翻页:
3 管理员信息CRUD
3.1 关键词查询
修改webui\src\main\webapp\WEB-INF\admin-page.jsp
<form action="admin/get/page.html" method="post" class="form-inline" role="form" style="float:left;">
<div class="form-group has-feedback">
<div class="input-group">
<div class="input-group-addon">查询条件</div>
<label>
<input name="keyword" class="form-control has-success" type="text" placeholder="请输入查询条件">
</label>
</div>
</div>
<button type="submit" class="btn btn-warning">
<i class="glyphicon glyphicon-search"></i> 查询
</button>
</form>
测试:
3.2 翻页时保持keyword
修改webui\src\main\webapp\WEB-INF\admin-page.jsp
// 跳转页面
window.location.href = "admin/get/page.html?pageNum="+pageNum+"&keyword=${param.keyword}";
3.3 删除管理员信息
删除按钮功能赋予:修改webui\src\main\webapp\WEB-INF\admin-page.jsp
<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>
修改component\src\main\java\com\atguigu\crowd\mvc\handler\AdminHandler.java
// 删除成员
@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;
}
增加remove()方法及实现类(IDEA快捷键前面两章已讲):
修改component\src\main\java\com\atguigu\crowd\service\impl\AdminServiceImpl.java
@Override
public void remove(Integer adminId) {
adminMapper.deleteByPrimaryKey(adminId);
}
3.4 新增管理员信息
在SQLyog中添加约束
ALTER TABLE `project_crowd`.`t_admin` ADD UNIQUE INDEX (`login_acct`);
新增按钮功能赋予:修改webui\src\main\webapp\WEB-INF\admin-page.jsp
<a href="admin/to/add/page.html" class="btn btn-success btn-xs">
<i class=" glyphicon glyphicon-check"></i>
</a>
修改webui\src\main\resources\spring-web-mvc.xml
<mvc:view-controller path="/admin/to/add/page.html" view-name="admin-add"/>
修改component\src\main\java\com\atguigu\crowd\mvc\handler\AdminHandler.java
// 新增成员
@RequestMapping("/admin/save.html")
public String save(Admin admin) {
adminService.saveAdmin(admin);
return "redirect:/admin/get/page.html?pageNum="+Integer.MAX_VALUE;
}
修改component\src\main\java\com\atguigu\crowd\service\impl\AdminServiceImpl.java
private final 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 创建时间
admin.setCreateTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
// 用户名已存在错误:
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);
}
}
}
在util\src\main\java\com\atguigu\crowd\exception新建LoginAcctAlreadyInUseException.java
package com.atguigu.crowd.exception;
/**
* 保存或更新Admin时如果检测到登录账号重复抛出这个异常
*/
public class LoginAcctAlreadyInUseException extends RuntimeException{
private static final long serialVersion = 1L;
public LoginAcctAlreadyInUseException() {
}
public LoginAcctAlreadyInUseException(String message) {
super(message);
}
public LoginAcctAlreadyInUseException(String message, Throwable cause) {
super(message, cause);
}
public LoginAcctAlreadyInUseException(Throwable cause) {
super(cause);
}
public LoginAcctAlreadyInUseException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
修改component\src\main\java\com\atguigu\crowd\mvc\config\CrowdExceptionResolver.java
@ExceptionHandler(value = LoginAcctAlreadyInUseException.class)
public ModelAndView resolveLoginAcctAlreadyInUseException(LoginAcctAlreadyInUseException exception,
HttpServletRequest request,
HttpServletResponse response) throws IOException {
String viewName = "admin-add";
return commonResolveException(viewName, exception, request, response);
}
测试:正常注册,确认后返回列表,显示新注册信息
SQLyog中可查:
如果重复注册相同用户名,则会报错:
3.5 更新管理员信息
新增更新功能赋予:修改webui\src\main\webapp\WEB-INF\admin-page.jsp
<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>
修改component\src\main\java\com\atguigu\crowd\mvc\handler\AdminHandler.java
@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";
}
@RequestMapping(value = "/admin/update.html")
public String update(Admin admin,
@RequestParam(value = "keyword",defaultValue = "") String keyword,
@RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum) {
adminService.update(admin);
return "redirect:/admin/get/page.html?pageNum="+pageNum+"&keyword="+keyword;
}
增加getAdminById()方法及实现类:
修改component\src\main\java\com\atguigu\crowd\service\impl\AdminServiceImpl.java
@Override
public Admin getAdminById(Integer adminId) {
return adminMapper.selectByPrimaryKey(adminId);
}
@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);
}
}
}
在util\src\main\java\com\atguigu\crowd\exception新建LoginAcctAlreadyInUseForUpdateException.java
package com.atguigu.crowd.exception;
public class LoginAcctAlreadyInUseForUpdateException extends RuntimeException{
private static final long serialVersion = 1L;
public LoginAcctAlreadyInUseForUpdateException() {
}
public LoginAcctAlreadyInUseForUpdateException(String message) {
super(message);
}
public LoginAcctAlreadyInUseForUpdateException(String message, Throwable cause) {
super(message, cause);
}
public LoginAcctAlreadyInUseForUpdateException(Throwable cause) {
super(cause);
}
public LoginAcctAlreadyInUseForUpdateException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
修改component\src\main\java\com\atguigu\crowd\mvc\config\CrowdExceptionResolver.java
@ExceptionHandler(value = LoginAcctAlreadyInUseForUpdateException.class)
public ModelAndView resolveLoginAcctAlreadyInUseForUpdateException(LoginAcctAlreadyInUseForUpdateException exception,
HttpServletRequest request,
HttpServletResponse response) throws IOException {
String viewName = "system-error";
System.out.println(viewName);
return commonResolveException(viewName, exception, request, response);
}
测试:点击任意数据进行更新
修改后可在SQLyog查询到修改后的数据:
如果修改已存在的账号,则会报错: