SSM第三季-SpringMVC-拦截器&静态资源放行&RestFul风格开发
SpringMVC
拦截器
配置拦截器
单一拦截器执行流程图
SpringMvc中的拦截器:
a) SpringMvc拦截器帮我们按照一定规则拦截请求,后根据开发人员自定义的拦截逻辑进行处理;
b) 自定义拦截器需要实现HandlerInterceptor接口;
c) 自定义的拦截器实现类需要在SpringMvc配置文件中配置;
d) 可以配置多个拦截器,配置的顺序会影响到拦截器的执行顺序,配置在前的先执行;
e) HandlerInterceptor有3个接口:
i. preHandle 预处理:在拦截方法前执行;
ii. postHandle 后处理:在拦截方法后执行;
iii. afterCompletion 渲染后处理:在页面渲染后执行;
f) 拦截器也体现了AOP思想;
g) 拦截器的应用:权限检查,日志记录,性能检测等;
在applicationContext.xml中配置拦截器
<mvc:interceptors>
<!-- 拦截器1 -->
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.sikiedu.interceptor.MyInterceptor1"/>
</mvc:interceptor>
<!-- 拦截器2 -->
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.sikiedu.interceptor.MyInterceptor2"/>
</mvc:interceptor>
</mvc:interceptors>
interceptor包
MyInterceptor1.java
package com.sikiedu.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
/**
* 自定义拦截器1
*/
public class MyInterceptor1 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println(" 1 preHandle 预处理 ");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println(" 1 postHandle 后处理 ");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println(" 1 afterCompletion 页面渲染后处理 ");
}
}
MyInterceptor2.java
package com.sikiedu.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
/**
* 自定义拦截器2
*/
public class MyInterceptor2 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println(" 2 preHandle 预处理 ");
return false;//false就中断后续执行了
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println(" 2 postHandle 后处理 ");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println(" 2 afterCompletion 页面渲染后处理 ");
}
}
控制台打印
1 preHandle 预处理
2 preHandle 预处理
1 afterCompletion 页面渲染后处理
因为MyInterceptor2.java中的preHandle返回值是false,所以拦截器1预处理跑到拦截器2预处理这里时拦截器2就断开了,然后继续执行拦截器1的页面渲染后处理
使用拦截器完成用户登陆效验&登陆异常处理
在bean包下创建user类
package com.sikiedu.bean;
public class User {
private String username;
private String password;
/*get和set方法*/
}
新建自定义异常类
MyLoginException.java
package com.sikiedu.exception;
/**
* 登录异常处理
*/
public class MyLoginException extends Exception {
private String msg;
private Object obj;
public Object getObj() {
return obj;
}
public String getMsg() {
return msg;
}
public MyLoginException(String msg) {
super();
this.msg = msg;
}
public MyLoginException(Object obj, String msg) {
super();
this.msg = msg;
this.obj = obj;
}
}
MyGlobalExceptionHandler.java
package com.sikiedu.exception;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* 自定义全局异常处理类
*
*/
@ControllerAdvice
public class MyGlobalExceptionHandler {
//处理自定义异常
@ExceptionHandler(MyLoginException.class)
String loginException(MyLoginException e, Model model) {
Object obj = e.getObj();
if(obj != null)
{
model.addAttribute("username", obj.toString());
}
model.addAttribute("errorMsg", e.getMsg());
//视图名
return "login_page";
}
}
在controller包下新建LoginController类
LoginController.java
package com.sikiedu.controller;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.sikiedu.bean.User;
import com.sikiedu.exception.MyLoginException;
/**
* 登录
*/
@Controller
@RequestMapping("/login/")
public class LoginController {
//登录请求
//登录成功 重定向到列表页
@RequestMapping(value = "login.do", method= RequestMethod.POST)
public String login(User u, HttpSession session) throws MyLoginException{
User user = new User();
user.setUsername("xueleng");
user.setPassword("123");
if(u.getUsername().equals(user.getUsername())) {
//用户名正确
if(u.getPassword().equals(user.getPassword())) {
session.setAttribute("user", u);
}
else {
//throw new MyLoginException("密码错误");
throw new MyLoginException(u.getUsername(), "密码错误");
}
}
else {
throw new MyLoginException("用户名错误");
}
//判断用户
/*if(u != null) {
session.setAttribute("user", u);
}*/
//重定向到列表页
return "redirect:/item/allList.do";
}
//登录失败 前往登录页面
@RequestMapping(value = "login.do", method= RequestMethod.GET)
public String login() {
//前往登录页面
return "login_page";
}
}
新建一个拦截器
LoginInterceptor.java
package com.sikiedu.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
/**
* 登录拦截器
*/
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
//获取请求
String URI = request.getRequestURI();
if(!URI.contains("login")) {
//不是登录请求 拦截
Object user = request.getSession().getAttribute("user");
if(user == null) {
//没有登录 重定向到登录页面 / 请求
response.sendRedirect(request.getContextPath()+"/login/login.do");
return false;
}
}
return true;
}
}
配置拦截器
<mvc:interceptors>
<!-- 登录验证拦截器 -->
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.sikiedu.interceptor.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
登陆页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta charset="UTF-8">
<title>登录/注册</title>
<meta name="viewport" content="initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- bootstrap framework -->
<link href="${pageContext.request.contextPath }/css/bootstrap.min.css" rel="stylesheet" media="screen">
<!-- elegant icons -->
<link href="${pageContext.request.contextPath }/css/style.css" rel="stylesheet" media="screen">
<!-- main stylesheet -->
<link href="${pageContext.request.contextPath }/css/main.min.css" rel="stylesheet" media="screen">
<!-- jQuery -->
<script src="${pageContext.request.contextPath }/js/jquery.min.js"></script>
</head>
<body class="login_page">
<div class="login_header">
</div>
<div class="login_register_form">
<div class="form_wrapper animated-short" id="login_form">
<h3 class="sepH_c"><span>Login</span> \ <a href="javascript:void(0)" class="form-switch" data-switch-form="register_form">Register</a></h3>
<form id="loginFrom" action="${pageContext.request.contextPath }/login/login.do" method="post">
<div class="input-group input-group-lg sepH_a">
<span class="input-group-addon"><span class="icon_profile"></span></span>
<input type="text" class="form-control" placeholder="Username" name="username" value="${username }">
</div>
<div class="input-group input-group-lg">
<span class="input-group-addon"><span class="icon_key_alt"></span></span>
<input type="password" class="form-control" placeholder="Password" name="password">
</div>
<div>
<a id="errorMsg" href="javascript:void(0)" style="color: red">${errorMsg}</a>
</div>
<div class="sepH_c text-right">
<a href="javascript:void(0)" class="small">Forgot password?</a>
</div>
<div class="form-group sepH_c">
<a href="javascript:doucment:loginFrom.submit()" class="btn btn-lg btn-primary btn-block">Log in</a>
</div>
</form>
</div>
<div class="form_wrapper animated-short" id="register_form" style="display:none">
<h3 class="sepH_c"><span>Register</span> \ <a href="javascript:void(0)" class="form-switch" data-switch-form="login_form">Login</a></h3>
<form name = "registerForm" action="${pageContext.request.contextPath}/userRegister" method="post">
<div class="input-group input-group-lg sepH_a">
<span class="input-group-addon"><span class="icon_profile"></span></span>
<input type="text" class="form-control" placeholder="Username" name="username">
</div>
<div class="input-group input-group-lg sepH_a">
<span class="input-group-addon"><span class="icon_key_alt"></span></span>
<input type="password" class="form-control" placeholder="Password" name="password">
</div>
<div class="input-group input-group-lg sepH_c">
<span class="input-group-addon"><span class="icon_mail_alt"></span></span>
<input type="email" class="form-control" placeholder="Email" name="email">
</div>
<div class="form-group sepH_c">
<a href="javascript:doucment:registerForm.submit()" class="btn btn-lg btn-success btn-block">Register</a>
</div>
</form>
</div>
</div>
<script>
$(function () {
$('.form-switch').on('click', function (e) {
e.preventDefault();
var $switchTo = $(this).data('switchForm'),
$thisForm = $(this).closest('.form_wrapper');
$('.form_wrapper').removeClass('fadeInUpBig');
$thisForm.addClass('fadeOutDownBig');
setTimeout(function () {
$thisForm.removeClass('fadeOutDownBig').hide();
$('#' + $switchTo).show().addClass('fadeInUpBig');
}, 300);
});
});
</script>
</body>
</html>
静态资源放行
a) 在web.xml配置DispatcherServlet的url-pattern以扩展名结尾,例如*.do
,*.html
等;
b) 在web.xml配置default servlet-mapping的url-pattern,以目录形式和扩展名形式;
<!-- 静态资源放行 -->
<!-- <servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/css/*</url-pattern>
<url-pattern>*.css</url-pattern>
<url-pattern>*.ttf</url-pattern>
<url-pattern>*.woff</url-pattern>
<url-pattern>*.js</url-pattern>
<url-pattern>*.png</url-pattern>
</servlet-mapping> -->
c) 在springmvc.xml中配置<mvc:resources/>
,该方法需要注意以下几点:
<!-- 静态资源放行 -->
<mvc:resources location="/css/" mapping="/css/**"/>
<mvc:resources location="/fonts/" mapping="/fonts/**"/>
<mvc:resources location="/js/" mapping="/js/**"/>
<mvc:resources location="/picture/" mapping="/picture/**"/>
i. 需要开启mvc:annotation-driven注解驱动;
<!-- 开启注解驱动 -->
<mvc:annotation-driven/>
ii. 如果配置了拦截器,需要在拦截器中进行过滤,否则会被拦截;
<!-- 登录验证拦截器 -->
<mvc:interceptor>
<mvc:mapping path="/**"/>
<!-- 排除一些文件|不拦截一些文件 -->
<mvc:exclude-mapping path="/**/*.css"/>
<mvc:exclude-mapping path="/**/*.js"/>
<mvc:exclude-mapping path="/**/*.png"/>
<mvc:exclude-mapping path="/**/*.tff"/>
<mvc:exclude-mapping path="/**/*.woff"/>
<bean class="com.sikiedu.interceptor.LoginInterceptor"/>
</mvc:interceptor>
iii. 路径名不要打错 ;
RestFul风格开发
RESTful风格开发:一种以URL定位资源的开发风格。使用RESTful开发URL会变得一目了然,更有层次,它不是标准或者协议;
使用RESTful前:
http://127.0.0.1/item/save
POST 新增物品http://127.0.0.1/item/delete
GET/POST 删除物品http://127.0.0.1/item/update
POST 修改物品
http://127.0.0.1/item/query.do?id=1
GET 根据id查询物品
使用RESTful后:
http://127.0.0.1/item
POST 新增物品http://127.0.0.1/item/1
DELETE 根据id删除物品http://127.0.0.1/item
PUT 修改物品http://127.0.0.1/item/1
GET 根据id查询物品
RESTful风格开发对Http协议中的基本方法的使用
POST INSERT 增 邮寄一个新的
DELETE DELETE 删 仍了,不要了
GET SELECT 查 获取一个
PUT UPDATE 改 往这个里边放点东西
使用Springmvc实现RESTful风格开发;
使用物品id当作请求路径,点击按钮,跳转到具体的页面;
在ItemController.java中添加一个方法
//使用restFul开发
//查询一个游戏信息,并且显示在内容页
新建一个item_info.jsp用于跳转页面测试
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h3>我是内容页</h3>
<input type="text" value="${item.item_id }">
<input type="text" value="${item.item_name }">
<input type="button" value="返回" οnclick="window.location='${pageContext.request.contextPath}/item/allList.do'">
</body>
</html>
修改主页面部分代码,添加一个input查询按钮用于跳转页面测试
<a herf="#" id="del_btn" class="btn btn-xs btn-danger" onclick="window.location='${pageContext.request.contextPath }/item/${item.item_id}'">查询</a>
页面效果
当点击查询按钮时,页面url跳转到<http://localhost:8080/ssm_project_springmvc/item/游戏的id>
当使用ajax时,页面不会跳转,需要到ajax回调中处理
修改主页面部分代码,添加一个input查询按钮和函数用于跳转页面测试
<a herf="#" id="del_btn" class="btn btn-xs btn-warning" onclick="restFul('${item.item_id}')">查询</a>
//restFul
function restFul(id) {
$.ajax({
type : "get",
url : "${pageContext.request.contextPath }/item/" + id,
success : function(data) {
//window.location="${pageContext.request.contextPath }/item/"+id;
alert(data.item_name);
}
});
}
修改controller中的方法
//使用restFul开发
//查询一个游戏信息,并且显示在内容页
@RequestMapping(value = "{item_id}", method=RequestMethod.GET)
@ResponseBody
public ItemInfo restFul(@PathVariable("item_id") String id, Model model) {
System.out.println("ajax " + id);
//查询
ItemInfo item = itemService.selectItemInfoById(id);
model.addAttribute("item", item);
//返回页面
//return "item_info";
return item;
}