目录
1、目标
2、思路
3、代码
3.1、创建工具方法 MD5 加密
3.2、创建登录失败异常类
3.2、在异常处理类中增加登录失败异常的处理
3.3、在登录页面显示异常消息
3.4、service 方法
3.5、创建登录成功的临时主页面?
3.6、handle 方法
3.7、测试
3.8、将临时主页面替换为真正的主页面
3.9、将登录成功后跳转到后台主页面的方式改为转发
3.9.1、修改 handle 方法
3.9.2、配置跳转到后台主页面的 view-controller
3.10、退出登录
3.10.1、修改主页面
3.10.2、增加 handle 方法
4、抽取后台主页面公共部分
4.1、include-head.jsp
4.2、include-nav.jsp
4.4、修改主页面
5、登录状态检查
5.1、目标
5.2、思路
5.3、代码
5.3.1、创建用户没有登录就访问受保护资源时抛出的异常类
5.3.2、创建拦截器类
5.3.3、注册拦截器类
5.4、完善配套的异常映射
5.4.1、基于 XML 的异常映射
5.4.2、基于注解的异常映射
1、目标
识别操作系统的人的身份,控制他的行为。
2、思路
3、代码
3.1、创建工具方法 MD5 加密
/**
* 对明文字符串进行MD5加密
* @param source 传入的明文字符串
* @return 加密结果
*/
public static String MD5(String source){
// 判断source是否有效
if(source == null || source.length() == 0){
// 不是有效字符串抛出异常
throw new RuntimeException(CrowdConstant.MESSAGE_STRING_INVALIDATE);
}
String algorithm = "md5";
try {
// 获取MessageDigest对象
MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
// 获取明文字符串对应的字节数组
byte[] input = source.getBytes();
// 加密
byte[] output = messageDigest.digest(input);
// 创建BigInteger对象
int signum = 1;
BigInteger bigInteger = new BigInteger(signum, output);
// 按照16进制将bigInteger转换为字符串
int radix = 16;
String encoded = bigInteger.toString(radix).toUpperCase();
return encoded;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
3.2、创建登录失败异常类
package com.atguigu.crowd.exception;
/**
* @Author zhang
* @Date 2022/5/3 - 22:27
* @Version 1.0
*/
import jdk.internal.org.objectweb.asm.commons.SerialVersionUIDAdder;
/**
* 登录失败抛出的异常
*/
public class LoginFailedException extends RuntimeException {
private static final long SerialVersionUIDAdder = 1L;
public LoginFailedException() {
}
public LoginFailedException(String message) {
super(message);
}
public LoginFailedException(String message, Throwable cause) {
super(message, cause);
}
public LoginFailedException(Throwable cause) {
super(cause);
}
public LoginFailedException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
3.2、在异常处理类中增加登录失败异常的处理
/**
* 处理登录失败异常
* @param exception 捕获到的异常类型
* @param request 当前请求对象
* @param response 当前响应对象
* @return
* @throws IOException
*/
@ExceptionHandler(value = LoginFailedException.class)
public ModelAndView resolveLoginFailedException(LoginFailedException exception, HttpServletRequest request, HttpServletResponse response) throws IOException {
String viewName = "admin-login";
return commonResolve(viewName, exception,request,response);
}
3.3、在登录页面显示异常消息
?
3.4、service 方法
/**
* 判断表单提交的账号密码是否合法
* @param loginAcct 表单提交的登录账号
* @param userPswd 表单提交的登录密码
* @return
*/
@Override
public Admin getAdminByLoginAcct(String loginAcct, String userPswd) {
// 根据登录账号查询Admin对象
AdminExample adminExample = new AdminExample();
AdminExample.Criteria criteria = adminExample.createCriteria();
criteria.andLoginAcctEqualTo(loginAcct);
List<Admin> list = adminMapper.selectByExample(adminExample);
// 判断Admin对象是否为null,若Admin对象为null则抛出异常
if(list == null || list.size() == 0){
throw new LoginFailedException(CrowdConstant.MESSAGE_LOGIN_FAILED);
}
if(list.size() > 1) {
throw new RuntimeException(CrowdConstant.MESSAGE_SYSTEM_ERROR_LOGIN_NOT_UNIQUE);
}
Admin admin = list.get(0);
if(admin == null){
throw new LoginFailedException(CrowdConstant.MESSAGE_LOGIN_FAILED);
}
// 若Admin对象不为null,则将数据库密码从Admin对象取出
String userPswdDB = admin.getUserPswd();
// 将表单提交的明文密码加密
String userPswdForm = CrowdUtil.MD5(userPswdDB);
// 将两个密码比较
if(!Objects.equals(userPswdForm, userPswdDB)){
// 两个密码不一致则抛出异常
throw new LoginFailedException(CrowdConstant.MESSAGE_LOGIN_FAILED);
}
// 若密码一致则返回admin对象
return admin;
}
3.5、创建登录成功的临时主页面?
<%--
Created by IntelliJ IDEA.
User: zhang
Date: 2022/5/4
Time: 0:55
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>临时主页面</h1>
${sessionScope.loginAdmin.userName}
</body>
</html>
3.6、handle 方法
package com.atguigu.crowd.mvc.handle;
import com.atguigu.crowd.constant.CrowdConstant;
import com.atguigu.crowd.entity.Admin;
import com.atguigu.crowd.service.api.AdminService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpSession;
/**
* @Author zhang
* @Date 2022/5/3 - 23:57
* @Version 1.0
*/
@Controller
public class AdminHandle {
@Autowired
private AdminService adminService;
@RequestMapping("/admin/do/login")
public String doLogin(
@RequestParam("loginAcct") String loginAcct,
@RequestParam("userPswd") String userPswd,
HttpSession session
){
// 调用service方法执行登录检查
Admin admin = adminService.getAdminByLoginAcct(loginAcct, userPswd);
// 将登录成功返回的admin对象存入Session域
session.setAttribute(CrowdConstant.ATTR_NAME_LOGIN_ADMIN, admin);
return "admin-main";
}
}
3.7、测试
3.8、将临时主页面替换为真正的主页面
保留以下内容,其他内容替换为资料中的内容
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>
修改:
①?
<base href="http://${pageContext.request.serverName}:${pageContext.request.serverPort}${pageContext.request.contextPath}/">
②?
${sessionScope.loginAdmin.userName}
3.9、将登录成功后跳转到后台主页面的方式改为转发
为了避免跳转到后台主页面再刷新浏览器导致重复提交登录表单,需要重定向到目标页面。?
3.9.1、修改 handle 方法
?修改 return 语句
@RequestMapping("/admin/do/login.html")
public String doLogin(
@RequestParam("loginAcct") String loginAcct,
@RequestParam("userPswd") String userPswd,
HttpSession session
){
// 调用service方法执行登录检查
Admin admin = adminService.getAdminByLoginAcct(loginAcct, userPswd);
// 将登录成功返回的admin对象存入Session域
session.setAttribute(CrowdConstant.ATTR_NAME_LOGIN_ADMIN, admin);
return "redirect:/admin/to/main/page.html";
}
3.9.2、配置跳转到后台主页面的 view-controller
<mvc:view-controller path="/admin/to/main/page.html" view-name="admin-main"/>
3.10、退出登录
3.10.1、修改主页面
admin-main.jsp
3.10.2、增加 handle 方法
AdminHandle
/**
* 退出登录
* @param session
* @return
*/
@RequestMapping("/admin/do/logout.html")
public String doLogout(HttpSession session){
// 强制session失效
session.invalidate();
// 重定向到登录页面
return "redirect:/admin/to/login/page.html";
}
4、抽取后台主页面公共部分
4.1、include-head.jsp
head 的公共部分?
<%--
Created by IntelliJ IDEA.
User: zhang
Date: 2022/5/4
Time: 17:34
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="">
<base href="http://${pageContext.request.serverName}:${pageContext.request.serverPort}${pageContext.request.contextPath}/">
<link rel="stylesheet" href="bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="css/font-awesome.min.css">
<link rel="stylesheet" href="css/main.css">
<style>
.tree li {
list-style-type: none;
cursor:pointer;
}
.tree-closed {
height : 40px;
}
.tree-expanded {
height : auto;
}
</style>
<script type="text/javascript" src="jquery/jquery-2.1.1.min.js"></script>
<script type="text/javascript" src="bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="script/docs.min.js"></script>
<script type="text/javascript" src="layer/layer.js"></script>
<script type="text/javascript">
$(function () {
$(".list-group-item").click(function(){
if ( $(this).find("ul") ) {
$(this).toggleClass("tree-closed");
if ( $(this).hasClass("tree-closed") ) {
$("ul", this).hide("fast");
} else {
$("ul", this).show("fast");
}
}
});
});
</script>
</head>
4.2、include-nav.jsp
<%--
Created by IntelliJ IDEA.
User: zhang
Date: 2022/5/4
Time: 17:36
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>
<nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<div class="container-fluid">
<div class="navbar-header">
<div><a class="navbar-brand" style="font-size:32px;" href="#">众筹平台 - 控制面板</a></div>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
<li style="padding-top:8px;">
<div class="btn-group">
<button type="button" class="btn btn-default btn-success dropdown-toggle" data-toggle="dropdown">
<i class="glyphicon glyphicon-user"></i> ${sessionScope.loginAdmin.userName} <span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu">
<li><a href="#"><i class="glyphicon glyphicon-cog"></i> 个人设置</a></li>
<li><a href="#"><i class="glyphicon glyphicon-comment"></i> 消息</a></li>
<li class="divider"></li>
<li><a href="admin/do/logout.html"><i class="glyphicon glyphicon-off"></i> 退出系统</a></li>
</ul>
</div>
</li>
<li style="margin-left:10px;padding-top:8px;">
<button type="button" class="btn btn-default btn-danger">
<span class="glyphicon glyphicon-question-sign"></span> 帮助
</button>
</li>
</ul>
<form class="navbar-form navbar-right">
<input type="text" class="form-control" placeholder="查询">
</form>
</div>
</div>
</nav>
<%--
Created by IntelliJ IDEA.
User: zhang
Date: 2022/5/4
Time: 17:37
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>
<div class="col-sm-3 col-md-2 sidebar">
<div class="tree">
<ul style="padding-left:0px;" class="list-group">
<li class="list-group-item tree-closed" >
<a href="main.html"><i class="glyphicon glyphicon-dashboard"></i> 控制面板</a>
</li>
<li class="list-group-item tree-closed">
<span><i class="glyphicon glyphicon glyphicon-tasks"></i> 权限管理 <span class="badge" style="float:right">3</span></span>
<ul style="margin-top:10px;display:none;">
<li style="height:30px;">
<a href="user.html"><i class="glyphicon glyphicon-user"></i> 用户维护</a>
</li>
<li style="height:30px;">
<a href="role.html"><i class="glyphicon glyphicon-king"></i> 角色维护</a>
</li>
<li style="height:30px;">
<a href="permission.html"><i class="glyphicon glyphicon-lock"></i> 菜单维护</a>
</li>
</ul>
</li>
<li class="list-group-item tree-closed">
<span><i class="glyphicon glyphicon-ok"></i> 业务审核 <span class="badge" style="float:right">3</span></span>
<ul style="margin-top:10px;display:none;">
<li style="height:30px;">
<a href="auth_cert.html"><i class="glyphicon glyphicon-check"></i> 实名认证审核</a>
</li>
<li style="height:30px;">
<a href="auth_adv.html"><i class="glyphicon glyphicon-check"></i> 广告审核</a>
</li>
<li style="height:30px;">
<a href="auth_project.html"><i class="glyphicon glyphicon-check"></i> 项目审核</a>
</li>
</ul>
</li>
<li class="list-group-item tree-closed">
<span><i class="glyphicon glyphicon-th-large"></i> 业务管理 <span class="badge" style="float:right">7</span></span>
<ul style="margin-top:10px;display:none;">
<li style="height:30px;">
<a href="cert.html"><i class="glyphicon glyphicon-picture"></i> 资质维护</a>
</li>
<li style="height:30px;">
<a href="type.html"><i class="glyphicon glyphicon-equalizer"></i> 分类管理</a>
</li>
<li style="height:30px;">
<a href="process.html"><i class="glyphicon glyphicon-random"></i> 流程管理</a>
</li>
<li style="height:30px;">
<a href="advertisement.html"><i class="glyphicon glyphicon-hdd"></i> 广告管理</a>
</li>
<li style="height:30px;">
<a href="message.html"><i class="glyphicon glyphicon-comment"></i> 消息模板</a>
</li>
<li style="height:30px;">
<a href="project_type.html"><i class="glyphicon glyphicon-list"></i> 项目分类</a>
</li>
<li style="height:30px;">
<a href="tag.html"><i class="glyphicon glyphicon-tags"></i> 项目标签</a>
</li>
</ul>
</li>
<li class="list-group-item tree-closed" >
<a href="param.html"><i class="glyphicon glyphicon-list-alt"></i> 参数管理</a>
</li>
</ul>
</div>
</div>
4.4、修改主页面
admin-main.jsp
5、登录状态检查
5.1、目标
将部分资源保护起来,让没有登录的请求不能访问。
5.2、思路
5.3、代码
5.3.1、创建用户没有登录就访问受保护资源时抛出的异常类
package com.atguigu.crowd.exception;
/**
* @Author zhang
* @Date 2022/5/4 - 17:54
* @Version 1.0
*/
/**
* 用户没有登录就访问受保护资源时抛出的异常
*/
public class AccessForbiddenException extends RuntimeException{
private static final long serialVersionUid = 1L;
public AccessForbiddenException() {
super();
}
public AccessForbiddenException(String message) {
super(message);
}
public AccessForbiddenException(String message, Throwable cause) {
super(message, cause);
}
public AccessForbiddenException(Throwable cause) {
super(cause);
}
protected AccessForbiddenException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
5.3.2、创建拦截器类
package com.atguigu.crowd.interceptor;
import com.atguigu.crowd.constant.CrowdConstant;
import com.atguigu.crowd.entity.Admin;
import com.atguigu.crowd.exception.AccessForbiddenException;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* @Author zhang
* @Date 2022/5/4 - 17:50
* @Version 1.0
*/
public class LoginInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 通过request对象或取Session对象
HttpSession session = request.getSession();
// 尝试从Session域中获取Admin对象
Admin admin = (Admin) session.getAttribute(CrowdConstant.ATTR_NAME_LOGIN_ADMIN);
// 判断admin对象是否为空
if(admin == null){
// 抛出异常
throw new AccessForbiddenException(CrowdConstant.MESSAGE_ACCESS_FORBIDDEN);
}
// admin对象不为空,则防行
return true;
}
}
5.3.3、注册拦截器类
<!-- 注册拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<!--
配置要拦截的资源
/* 对应一层路径,如:/aaa
/** 对应任意层路径,如:/aaa/bbb
-->
<mvc:mapping path="/**"/>
<!-- 配置不拦截的资源 -->
<mvc:exclude-mapping path="/admin/to/login/page.html"/> <!-- 登录页面 -->
<mvc:exclude-mapping path="/admin/do/login.html"/> <!-- 执行登录的操作 -->
<mvc:exclude-mapping path="/admin/do/logout.html"/> <!-- 退出登录 -->
<!-- 配置拦截器类 -->
<bean class="com.atguigu.crowd.interceptor.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
5.4、完善配套的异常映射
5.4.1、基于 XML 的异常映射
<!-- 配置基于XML的异常映射 -->
<bean id="simpleMappingExceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!-- 配置异常类型和具体视图页面的对应关系 -->
<property name="exceptionMappings">
<props>
<!-- key属性指定异常的全类名 标签体中写对应的视图(去掉前后缀) -->
<prop key="java.lang.Exception">system-error</prop>
<prop key="com.atguigu.crowd.exception.AccessForbiddenException">admin-login</prop>
</props>
</property>
</bean>
5.4.2、基于注解的异常映射
/**
* 未登录访问受保护资源
* @param exception
* @param request
* @param response
* @return
* @throws IOException
*/
@ExceptionHandler(value = AccessForbiddenException.class)
public ModelAndView resolveAccessForbiddenException(AccessForbiddenException exception, HttpServletRequest request, HttpServletResponse response) throws IOException {
String viewName = "admin-login";
return commonResolve(viewName, exception, request, response);
}
|