SpringMVC(二) 頁面轉(zhuǎn)發(fā)、重定向哆窿、異步链烈、Restful、異常處理挚躯、攔截器
頁面跳轉(zhuǎn)之轉(zhuǎn)發(fā)
方式一:簡單方式
- 頁面
<a href="${pageContext.request.contextPath}/respServlet/forward1">普通轉(zhuǎn)發(fā)</a>
- 后臺
//頁面轉(zhuǎn)發(fā)方式1
@RequestMapping("/respServlet/forward1")
public String forward1() {
return "success";
}
方式二:使用forward轉(zhuǎn)發(fā)
在返回中使用forward:url表示使用forward轉(zhuǎn)發(fā)
- 頁面
<a href="${pageContext.request.contextPath}/respServlet/forward2">forward轉(zhuǎn)發(fā)</a>
- 后臺
@RequestMapping("/forward2")
public String forward2() {
return "forward:/WEB-INF/fail.jsp";
}
方式三:使用Servlet原生API
通過SpringMVC前端控制器傳遞回來的參數(shù)可以接收到HttpServletRequest HttpServletResponse對象强衡,使用ServletAPI可以進(jìn)行轉(zhuǎn)發(fā)
- 頁面
<a href="${pageContext.request.contextPath}/respServlet/forward3">Servlet原生API</a>
- 后臺
@RequestMapping("/forward3")
public void forward3(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
request.getRequestDispatcher("/WEB-INF/fail.jsp")
.forward(request, response);
}
轉(zhuǎn)發(fā)攜帶數(shù)據(jù)
進(jìn)行頁面轉(zhuǎn)發(fā)時,通常我們都會攜帶數(shù)據(jù)码荔,SpringMVC中我們
- 可以使用HttpServletRequest request
@RequestMapping("/forward4")
public String forward4(HttpServletRequest request) {
//使用Request傳值
request.setAttribute("pageValue", "zs");
return "success";
}
- 還可以使用Model 對象
@RequestMapping("/forward5")
public String forward5(Model model) {
//傳遞數(shù)據(jù)
model.addAttribute("pageValue", "ss");
return "success";
}
- 還可以使用ModelAndView對象
@RequestMapping("/forward6")
public ModelAndView forward6() {
//構(gòu)造ModelAndView對象
ModelAndView modelAndView = new ModelAndView();
//設(shè)置數(shù)據(jù)
modelAndView.addObject("pageValue", "fromModelAndView");
//設(shè)置邏輯視圖
modelAndView.setViewName("success");
return modelAndView;
}
頁面跳轉(zhuǎn)之重定向
使用redirect重定向
在Controller的返回中使用 redirect:url代表頁面重定向
- 頁面
<a href="${pageContext.request.contextPath}/respServlet/redirect1">redirect重定向</a>
- 后臺
@RequestMapping("/redirect1")
public String redirect1() {
return "redirect:/success.jsp";
}
使用Servlet原生API
- 頁面
<a href="${pageContext.request.contextPath}/respServlet/redirect2">使用Servlet原生API</a>
- 后臺
@RequestMapping("/redirect2")
public void redirect2(HttpServletRequest request,
HttpServletResponse response) throws IOException {
response.sendRedirect(request.getContextPath() + "/success.jsp");
}
使用重定向的方式進(jìn)入外界無法訪問的WEB-INF目錄下
我們知道在javaWeb項(xiàng)目中漩勤,WEB-INF目錄下的資源是無法通過外界訪問的。但是可以通過服務(wù)器內(nèi)部的請求轉(zhuǎn)發(fā)訪問到目胡,現(xiàn)在我們想使用頁面重定向技術(shù)進(jìn)行訪問WEB-INF目錄下的資源锯七。我們可以經(jīng)過一次轉(zhuǎn)發(fā)來達(dá)到通過重定向技術(shù)來訪問WEB-INF目錄下的資源
- 頁面
<a href="${pageContext.request.contextPath}/respServlet/redirect3">使用重定向-轉(zhuǎn)發(fā)來訪問WEB-INF下的資源</a>
-
后臺
@RequestMapping("/redirect3") public String redirect3() { return "redirect:/respServlet/redirforwardtoSuccess"; } //轉(zhuǎn)發(fā)方法 @RequestMapping("/redirforwardtoSuccess") public String redirectForward() { //轉(zhuǎn)發(fā)到指定資源中 return "forward:/WEB-INF/fail.jsp"; }
釋放靜態(tài)資源
當(dāng)有靜態(tài)資源需要加載時,比如js css 等誉己,如果在url-pattern中配置的是/眉尸,代表除了.jsp請求不攔截,其他的所有請求都會攔截巨双,包括一些靜態(tài)文件噪猾,而攔截之后,SpringMVC又找不到對應(yīng)的處理器來處理筑累,因此我們需要釋放靜態(tài)資源袱蜡,來讓靜態(tài)資源能夠被正常加載
方式一
<!--
釋放資源:
mapping:代表匹配的路徑規(guī)則
location:代表匹配的路徑規(guī)則的靜態(tài)資源的位置
-->
<mvc:resources mapping="/js/*" location="/js/"/>
方式二
指定處理器映射器尋找不到對應(yīng)的處理方法時,暫時不要報錯慢宗,而是直接丟給外部的默認(rèn)Servlet,也就是tomcat處理
<!-- 指定錯誤交給外部的處理器處理-->
<mvc:default-servlet-handler/>
Ajax+json實(shí)現(xiàn)異步交互
在SpringMVC中坪蚁,前端發(fā)送Ajax異步請求,后端返回json響應(yīng)镜沽。這個功能主要是通過兩個注解@RequestBody和@ResponseBody實(shí)現(xiàn)的
SpringMVC默認(rèn)使用MappingJackson2HttpMessageConverter對json數(shù)據(jù)進(jìn)行轉(zhuǎn)換敏晤,需要加入jackson的包
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
@RequestBody接收ajax請求
@RequestBody用于接收前端傳遞的請求體重的json數(shù)據(jù),并可以自動轉(zhuǎn)換封裝進(jìn)指定的對象中
- 頁面
- 其中contentType代表請求參數(shù)類型
- dataType代表響應(yīng)數(shù)據(jù)類型
<button id="btn_ajax">提交ajax請求</button>
<script src="/js/jquery-3.3.1.js"></script>
<script>
$(function () {
$("#btn_ajax").click(function () {
$.ajax({
type: "POST",
url: "${pageContext.request.contextPath}/respServlet/ajaxReq",
contentType: "application/json",
dataType: "json",
data: '[{"name":"張三","age":19},{"name":"李四","age":19}]',
success: function (data) {
console.log(data);
alert(data);
}
});
});
});
</script>
- 封裝實(shí)體類
public class User {
private String name;
private Integer age;
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
- 后臺
@ResponseBody
@RequestMapping("/ajaxReq")
public List<User> ajaxReq(@RequestBody List<User> users) {
System.out.println("");
users.stream().forEach(user -> System.out.println(user));
return users;
}
@ResponseBody返回Json數(shù)據(jù)
@responseBody用于將controller方法返回的對象通過轉(zhuǎn)換器轉(zhuǎn)換為指定的格式(通常為json)缅茉,
@ResponseBody
@RequestMapping("/ajaxReqStr")
public String ajaxReqStr(@RequestBody User user) {
System.out.println(user);
return "ok";
}
Spring還提供了一個@RestController 表示@Controller+@ResponseBody
Restful風(fēng)格
定義
REST是一種軟件架構(gòu)風(fēng)格嘴脾,其強(qiáng)調(diào)HTTP應(yīng)當(dāng)以資源為中心
REST規(guī)范了HTTP請求動作,使用四個詞語分別表示對資源的CRUD操作
也就是說Restful風(fēng)格是通過方法的method類型來區(qū)分各種不同的業(yè)務(wù)
原來 | Restful | |
---|---|---|
保存 | /saveUser | post /usr |
修改 | /updateUser?id=1 | Put /user/1 |
刪除 | /deleteUser?id=1 | delete /user/1 |
查詢所有 | /findAllUser | get /user |
查詢一個 | /findUserById?id=1 | get /user/1 |
保存
- 頁面
$("#save").click(function () {
$.ajax({
type: "POST",
url: "${pageContext.request.contextPath}/user",
contentType: "application/json",
dataType: "text",
data: '{"name":"user1","age":11}',
success: function (data) {
alert(data);
}
});
})
- 后臺
注解@PostMapping 相當(dāng)于@RequestMapping(value="/user" method="POST")
@PostMapping("/user") //@PostMapping 相當(dāng)于 @RequestMapping(value = "/user",method = RequestMethod.POST)
@ResponseBody
public String saveUser(@RequestBody User user) {
System.out.println("收到的參數(shù)" + user);
return "ok";
}
查詢
get請求沒有請求體,所以參數(shù)需要在請求地址中傳遞
- 頁面
$("#find").click(function () {
$.ajax({
type: "GET",
url: "${pageContext.request.contextPath}/user/name/user1/age/11",
contentType: "application/json",
dataType: "text",
success: function (data) {
alert(data);
}
});
});
- 后臺
@GetMapping("/user/name/{name}/age/{age}")
@ResponseBody
public String findUser(@PathVariable String name,
@PathVariable String age) {
System.out.println("接收到的參數(shù)" + name + age);
return "ok";
}
異常處理機(jī)制
Spring框架译打,我們通常將異常拋到框架中耗拓,然后指定Spring的異常處理器來統(tǒng)一處理異常
方式一:自定義異常處理器
可以實(shí)現(xiàn)HandlerExceptionResolver接口,實(shí)現(xiàn)接口方法來自定義異常處理器
public class MyExceptionHandler implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
return new ModelAndView("error", "err", e.getMessage());
}
}
- 加入掃描注解
<context:component-scan base-package="com.itheima.exceptionhandler"/>
方式二:@ControllerAdvice
使用注解@ControllerAdvice注解 @ExceptionHandler(Exception.class)
@ControllerAdvice
public class MyExceptionHandler2 implements HandlerExceptionResolver {
//聲明處理哪些異常
@ExceptionHandler(Exception.class)
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
return new ModelAndView("WEB-INF/error", "err", e.getMessage());
}
}
攔截器
什么是攔截器
攔截器是Spring提供的一種技術(shù)奏司,類似于Servlet的Filter
攔截器的特點(diǎn)
- 會在請求進(jìn)入controller之前
- 離開controller之后
- 頁面渲染完畢之后
自定義攔截器
自定義一個類實(shí)現(xiàn)HandlerInterceptor接口
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("進(jìn)入控制器之前");
//代表是否放心 true 代表放行 false代表不放心
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("離開控制器之后");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("頁面渲染完成之后");
}
}
- Springmvc中配置攔截規(guī)則
<!-- 配置攔截器-->
<mvc:interceptors>
<mvc:interceptor>
<!-- 要攔截的路徑規(guī)則 /**代表攔截所有-->
<mvc:mapping path="/**"/>
<!-- 不攔截的路徑規(guī)則-->
<mvc:exclude-mapping path="/login"/>
<!-- 指定攔截器-->
<bean class="com.itheima.interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
自定義攔截器鏈
開發(fā)中攔截器可以單獨(dú)使用乔询,也可以同時使用多個攔截器形成一條攔截器鏈
開發(fā)步驟和單個攔截器是一樣的,只不過注冊多個攔截器的時候韵洋,注冊的順序代表攔截器的執(zhí)行順序
- 定義第二個攔截器
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:mapping path="/register"/>
<bean class="com.itheima.interceptor.MyInterceptor2"/>
</mvc:interceptor>
攔截器和過濾器的區(qū)別
- 攔截器屬于SpringMVC框架哥谷,只有使用了SpringMVC框架才能使用攔截器,Servlet屬于JavawebAPI 只要是JavaWeb工程都可以使用
- 過濾器在url-pattern中配置了/之后麻献,可以對所有資源攔截,攔截器配置了/ 之后 只會攔截訪問的控制器方法猜扮,不會攔截靜態(tài)資源
案例 使用攔截器完成用戶訪問的攔截
req:
- 用戶訪問一個頁面index.jsp
- 如果用戶已經(jīng)登錄勉吻,可直接進(jìn)入index.jsp
- 如果用戶沒有登錄,跳轉(zhuǎn)到登錄頁面
- 頁面
- login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/login" method="post">
用戶名:<input type="text" name="username"><br/>
密碼:<input type="text" name="password"><br/>
<input type="submit" value="提交">
</form>
</body>
</html>
- index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
登錄完成 ${username}
</body>
</html>
- 后臺Controller
@Controller
public class UserController {
@RequestMapping("/login")
public String login(String username, String password, HttpSession session) {
if (username != null && !username.equals("")) {
if (username.equals("admin")) {
//登錄成功 存入session
session.setAttribute("loginName", username);
return "forward:/index";
}
}
return "redirect:/login.jsp";
}
@RequestMapping("/index")
public String toIndex() {
return "WEB-INF/index";
}
}
- 攔截器
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//判斷是否已經(jīng)存儲
String loginName = (String) request.getSession().getAttribute("loginName");
if (loginName != null && !"".equals(loginName)) {
//不為空 放行
return true;
} else {
//為空 重定向到登錄頁面
response.sendRedirect(request.getContextPath() + "/login.jsp");
return false;
}
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
- 攔截器配置
<!-- 配置攔截器-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/login"/>
<bean class="com.itheima.interceptor.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>