1. jdbc url地址参数
jdbc.url=jdbc:mysql://localhost:3306/atcrowdfunding190105?rewriteBatchedStatements=true&useUnicode=true&characterEncoding=utf8
- rewriteBatchedStatements设置为true表示允许多条SQL语句使用“;”分开一起发送给数据库执行。
- useUnicode和characterEncoding设置数据库连接使用的字符集是UTF-8
2. Maven Jar包下载失败相关【重要】
2.1 明显的下载失败
2.1.1 具体表现
在Maven仓库中如果看到jar包或其他相关文件是以“lastUpdated”作为扩展名结尾,说明jar包或其他相关文件下载失败。
2.1.2 原因分析
- Maven在下载jar包的过程中,文件会以lastUpdated作为临时扩展名。文件下载完成后,Maven会将“lastUpdated”扩展名去掉。
- 如果下载一半连不上网,导致下载失败,那么Maven就放任文件保持临时扩展名“lastUpdated”不管。
- 当我们下一次强制要求Maven重新下载jar包时候,Maven看到这个文件以“lastUpdated”结尾,那么Maven就会无视“下载”命令。
- 所以对于以“lastUpdated”为扩展名的文件需要手动删除,然后再让Maven重新下载。
2.1.3 应对方法
- 基本做法:删除以“lastUpdated”结尾的文件,重新下载。
- 问题:Maven仓库使用一段时间后,以“lastUpdated”结尾的文件会非常多,手动删除不现实。
- 正确做法:借助clearLastUpdated.bat脚本文件批量处理。
2.1.4 clearLastUpdated.bat文件设置
- 将clearLastUpdated.bat文件放入Maven仓库根目录
- 使用文本编辑器打开
- 修改下面两项
- SET CLEAR_PATH=D:
- SET CLEAR_DIR=D:\RepMaven0105
CLEAR_PATH设置为Maven仓库所在盘符
CLEAR_DIR设置为Maven仓库的根目录,一定要使用非中文没有空格的目录
2.1.5 需要注意的问题
- 如果依赖信息写错,世界上并不存在这个依赖对应的jar包,无论重试多少次都无法下载成功。
- 所以如果多次尝试下载,在网络和其他jar包下载都正常的情况下,特定某一个jar包始终下载失败,则很有可能是依赖信息写错了。
2.2 下载完成但内部文件损坏
2.2.1 具体表现
- 表面上看起来,jar包并不是以“lastUpdated”结尾,表示已经下载完成。但是,程序编译或运行的时候报错。比如:找不到xxx类错误,而且通常这个类不是我们编写的;又或者找不到xxx方法,而且通常这个方法不是我们编写的。
- 其他表现往往还体现为一些莫名其妙的错误,特别是往往和我们编写的代码没有直接关系。
2.2.2 确诊
- 到Maven仓库中找到疑似下载失败的jar包
- 使用文件校验工具文件校验
- 打开工具
- 将要验证的jar包拖拽进工具界面
- 比较SHA1值
- 一致:确定jar包下载成功,内部正确没问题
- 不一致:确定jar包内部损坏
2.3 HASH加密原理
明文→加密→密文
HASH加密方式特点:
- 包含一系列具体的加密算法,例如:MD5、SHA1、CRC32等等,彼此之间的区别是加密强度不同,具体体现为密文长度长短不一
- 不可逆:不能通过密文反推出明文
- 在算法确定的前提下,输入不变,输出不变
- 在算法确定的前提下,输入发生非常细微的变化,输出一定会变,校验文件就是基于这个特性。服务器端加密结果如果和本地加密结果不一致,那么一定可以断定下载过程中数据发生了错误。
- 在算法确定的前提下,不管输入的数据有多大还是多小,输出结果长度固定。
2.4 根据依赖信息定位jar包在仓库里位置
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.1</version>
jar包所在目录:Maven仓库根目录/org/apache/commons/commons-lang3/3.1
2.5 强制重新下载jar包
2.5.1 删除jar包
根据上面描述找到jar包所在位置,删除jar包所在目录中的全部文件。
2.5.1 在IDE中执行Maven刷新
3. 显示首页
3.1 执行流程
3.3 创建PortalHandler
所在工程:atcrowdfunding-admin-2-component
全类名:com.rgh.crowd.funding.handler.PortalHandler
-
代码
@Controller public class PortalHandler { @RequestMapping("/index") public String showIndex(){ //从数据加载页面需要显示的数据 return "index-page"; } }
3.3 创建index-page.jsp
将原型index.html页面的内容复制进去。
所在工程:atcrowdfunding-admin-1-webui
-
文件位置:
3.4 调整index-page.jsp
<html lang="GB18030">改成<html lang="UTF-8">
<meta charset="GB18030">改成<meta charset="UTF-8">
添加<title>❤汇聚点滴的力量,成就非凡的伟业❤</title>
3.5 处理样式和JavaScript相关
3.5.1 第一步:样式和JavaScript文件
所在工程:atcrowdfunding-admin-1-webui
从原型中直接复制到项目中
3.5.2 第二步:刷新页面
此时应该能正常访问
4. 解决页面路径问题
4.1 方案一
将contextPath存入application域
- 在一个自定义监听器中将context.getContextPath()返回值存入application域,属性名是appPath。
- 在页面上使用${appPath}获取。
- 路径写法成为:${appPath}/xxx/xxx/xxx
4.2 方案二
4.2.1 写法
<base href="http://${pageContext.request.serverName}:${pageContext.request.serverPort}${pageContext.request.contextPath}/"/>
4.2.2 注意点
base标签需要放在head标签内
base标签必须放在所有带路径的标签前面
serverName和serverPort之间必须有“:”
-
contextPath前:不能有“/”
- 因为contextPath本身就是“/”开头的,再写会多一个,导致Cookie的路径不一致,进而导致Session不能正常工作
-
contextPath后:必须有“/”
- 带路径的标签,如果路径以“/”开头,则不参考base标签。又因为具体标签中的路径和base标签中的路径拼起来以后必须是有效、完整的路径,所以“/”要放在base标签的路径最后
5. 登陆功能
5.1 修改登陆超链接
- 所在工程:atcrowdfunding-admin-1-webui
- 所在文件:/atcrowdfunding-admin-1-webui/src/main/webapp/WEB-INF/index-page.jsp
<ul class="nav navbar-nav navbar-right">
<li><a href="login.html">登录</a></li>
<li><a href="reg.html">注册</a></li>
<li><a>|</a></li>
<li><a href="admin/to/login/page.html">管理员登录</a></li>
</ul>
5.2 使用view-controller实现页面跳转
spring-web-mvc.xml文件中加入。注意:path属性要求必须带扩展名,后缀是html。
<!--
@RequestMapping("/admin/to/login/page")
public String toLoginPage() {
return "admin-login";
}
-->
<mvc:view-controller path="/admin/to/login/page.html" view-name="admin-login"/>
5.3 登陆页面代码
admin-login.jsp
form表单
<form action="admin/do/login.html" class="form-signin" role="form">
<h2 class="form-signin-heading"><i class="glyphicon glyphicon-log-in"></i> 管理员登录</h2>
<p>${requestScope.MESSAGE}</p>
<div class="form-group has-success has-feedback">
<input
type="text"
name="loginAcct"
class="form-control"
id="inputSuccess4"
placeholder="请输入登录账号" autofocus>
<span class="glyphicon glyphicon-user form-control-feedback"></span>
</div>
<div class="form-group has-success has-feedback">
<input
type="text"
name="userPswd"
class="form-control"
id="inputSuccess4"
placeholder="请输入登录密码"
style="margin-top:10px;">
<span class="glyphicon glyphicon-lock form-control-feedback"></span>
</div>
<button class="btn btn-lg btn-success btn-block">登录</button>
</form>
5.4 登陆流程分析
5.5 MD5加密的工具方法
- 所在工程:atcrowdfunding-admin-3-common
- 全类名:com.atguigu.crowd.funding.util.CrowdFundingUtils
public class CrowdFundingUtils {
/**
* 判断Map是否有效
* @param map 待验证的Map
* @param <K>
* @param <V>
* @return true代表有效,false代表无效
*/
public static <K,V> boolean mapEffective(Map<K,V> map){
return map != null && map.size()>0;
}
/**
* 判断集合是否有效
* @param collection 待验证的集合
* @param <E>
* @return true代表有效,false代表无效
*/
public static <E> boolean collectionEffective(Collection<E> collection){
return collection != null && collection.size()>0;
}
/**
* 判断字符串是否有效
* @param source 待验证字符串
* @return true表示有效,false表示无效
*/
public static boolean stringEffective(String source){
return source != null && source.length()>0;
}
/**
* MD5加密工具方法
* @param source 明文
* @return 密文
*/
public static String md5(String source){
//判断传入的明文字符串是否有效
if(!stringEffective(source)){
throw new RuntimeException("明文不是有效字符串,请核对后再操作");
}
//声明StringBuilder待用
StringBuilder builder = new StringBuilder();
//准备字符数组
char[] characters = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
String algorithm = "MD5";
try {
//执行加密的核心对象
MessageDigest digest = MessageDigest.getInstance(algorithm);
//将要加密的明文转换成字节数组的形式
byte[] inputBytes = source.getBytes();
//执行加密
byte[] outputBytes = digest.digest(inputBytes);
//遍历outputBytes
for (int i = 0;i<outputBytes.length;i++){
//获取当前字节数值
byte b = outputBytes[i];
//获取低4位的值
int lowValue = b & 15;
//获取高四位的值
int hightValue = (b >> 4) & 15;
//以高四位,低四位的值为下标从字符数组中获取对应字符
char highCharacter = characters[hightValue];
char lowCharacter = characters[lowValue];
//拼接
builder.append(highCharacter).append(lowCharacter);
}
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return builder.toString();
}
}
5.6 handler方法
- 所在工程:atcrowdfunding-admin-2-component
- 全类名:com.atguigu.crowd.funding.handler.AdminHandler
@RequestMapping("/admin/do/login")
public String doLogin(@RequestParam("loginAcct") String loginAcct,
@RequestParam("userPswd") String userPswd,
Model model,
HttpSession session){
//调用adminService的login方法执行登陆业务逻辑,返回查询到的Admin对象
Admin admin = adminService.login(loginAcct,userPswd);
//判断admin是否为null
if(admin == null){
model.addAttribute("MESSAGE","登陆账号或密码不正确!请核对后再登陆");
return "admin-login";
}
session.setAttribute("LOGIN-ADMIN",admin);
return "admin-main";
}
注意:HttpSession要求导入servlet-api才能够正常使用
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<scope>provided</scope>
</dependency>
provided依赖不能传递,只能在有需要的工程单独加入
5.7 service方法
public Admin login(String loginAcct, String userPswd) {
//根据loginAcct查询数据库
AdminExample adminExample = new AdminExample();
adminExample.createCriteria().andLoginAcctEqualTo(loginAcct);
List<Admin> list = adminMapper.selectByExample(adminExample);
if(!CrowdFundingUtils.collectionEffective(list)){//!false=true集合无效
return null;
}
//获取唯一集合元素
Admin admin = list.get(0);
if(admin == null){
return null;
}
//比较密码
String userPswdDataBase = admin.getUserPswd();//数据中查的
String userPswdBroswer = CrowdFundingUtils.md5(userPswd);//页面传的加密
if(Objects.equals(userPswdBroswer,userPswdDataBase)){
//密码相当登陆成功
return admin;
}
return null;
需要在spring-persist-tx.xml配置文件中加入事务属性配置
<tx:method name="login" read-only="true"/>
5.8 后台主页面
所在工程:atcrowdfunding-admin-1-webui
-
文件位置:
-
内容:
<title>❤汇聚点滴的力量,成就非凡的伟业❤</title> </head> <body> <h1>后台主页面</h1> ${sessionScope['LOGIN-ADMIN'] } </body> </html>
6. 登陆的辅助功能
6.1 常量声明
所在工程:atcrowdfunding-admin-3-common
全类名:com.rgh.crowd.funding.util.CrowdFundingConstant
-
内容:
public class CrowdFundingConstant { public static final String ATTR_NAME_MESSAGE = "MESSAGE"; public static final String ATTR_NAME_LOGIN_ADMIN = "LOGIN-ADMIN"; public static final String MESSAGE_LOGIN_FAILED = "登录账号或密码不正确!请核对后再登录!"; public static final String MESSAGE_CODE_INVALID = "明文不是有效字符串,请核对后再操作!"; public static final String MESSAGE_ACCESS_DENIED = "请登录,再操作!"; }
6.2 配置异常映射机制
作用:将捕获到的异常类型和具体页面对应起来。在捕获到对应类型的异常后,跳转到对应页面。
配置:XML方式(只能返回页面,很难兼容Ajax请求)
配置:Annotation方式(兼容两种请求)
所在工程:atcrowdfunding-admin-2-component
全类名:com.rgh.crowd.funding.exception.CrowFundingExceptionResolever
-
内容:
@ControllerAdvice public class CrowFundingExceptionResolever { @ExceptionHandler(value=Exception.class) public ModelAndView catchException(Exception exception){ ModelAndView mav = new ModelAndView(); mav.addObject("exception",exception); mav.setViewName("system-error"); return mav; } }
6.3 错误信息页面
system-error.jsp
<script type="text/javascript" src="jquery/jquery-2.1.1.min.js"></script>
<script type="text/javascript">
$(function(){
$("#bakcBtn").click(function(){
window.history.back();
});
});
</script>
<h1>${requestScope.exception.message }</h1>
<button id="bakcBtn" class="btn btn-lg btn-success btn-block">后退</button>
6.4 退出登陆操作
- 所在工程:atcrowdfunding-admin-2-component
- 所在类:com.rgh.crowd.funding.handler.AdminHandler
- 内容:
@RequestMapping("/admin/logout")
public String logout(HttpSession session){
session.invalidate();
return "redirect:/index.html";
}
6.5 登陆检出拦截器
说明:仅仅是临时使用,练习拦截器。将来使用SpringSecurity后将取消。
6.5.1 拦截器类
所在工程:atcrowdfunding-admin-2-component
全类名:com.rgh.crowd.funding.interceptor.LoginInterceptor
-
内容:
public class LoginInterceptor extends HandlerInterceptorAdapter{ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session = request.getSession(); Admin admin = (Admin) session.getAttribute(CrowdFundingConstant.ATTR_NAME_LOGIN_ADMIN); if(admin == null){ request.setAttribute(CrowdFundingConstant.ATTR_NAME_MESSAGE,CrowdFundingConstant.MESSAGE_ACCESS_DENIED); request.getRequestDispatcher("/WEB-INF/admin-login.jsp").forward(request,response); return false; } return true; } }
6.5.2 注册拦截器
所在工程:atcrowdfunding-admin-1-webui
-
配置文件:spring-web-mvc.xml
<!-- 配置拦截器 --> <mvc:interceptors> <mvc:interceptor> <!--设置当前要拦截的路径--> <mvc:mapping path="/**"/> <!--设置不需要拦截的路径--> <mvc:exclude-mapping path="/index.html"/> <mvc:exclude-mapping path="/admin/to/login/page.html"/> <mvc:exclude-mapping path="/admin/do/login.html"/> <mvc:exclude-mapping path="/admin/logout.html"/> <!--拦截器的bean--> <bean class="com.rgh.crowd.funding.interceptor.LoginInterceptor"/> </mvc:interceptor> </mvc:interceptors>