SpringMVC(二) 頁面轉(zhuǎn)發(fā)吓坚、重定向撵幽、異步、Restful礁击、異常處理盐杂、攔截器

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>
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末旅赢,一起剝皮案震驚了整個濱河市齿桃,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌煮盼,老刑警劉巖短纵,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異僵控,居然都是意外死亡香到,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進(jìn)店門报破,熙熙樓的掌柜王于貴愁眉苦臉地迎上來悠就,“玉大人,你說我怎么就攤上這事充易」Fⅲ” “怎么了?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵盹靴,是天一觀的道長炸茧。 經(jīng)常有香客問我,道長稿静,這世上最難降的妖魔是什么梭冠? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮自赔,結(jié)果婚禮上妈嘹,老公的妹妹穿的比我還像新娘。我一直安慰自己绍妨,他們只是感情好润脸,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布柬脸。 她就那樣靜靜地躺著,像睡著了一般毙驯。 火紅的嫁衣襯著肌膚如雪倒堕。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天爆价,我揣著相機(jī)與錄音垦巴,去河邊找鬼。 笑死铭段,一個胖子當(dāng)著我的面吹牛骤宣,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播序愚,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼憔披,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了爸吮?” 一聲冷哼從身側(cè)響起芬膝,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎形娇,沒想到半個月后锰霜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡桐早,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年癣缅,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片哄酝。...
    茶點(diǎn)故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡所灸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出炫七,到底是詐尸還是另有隱情爬立,我是刑警寧澤,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布万哪,位于F島的核電站侠驯,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏奕巍。R本人自食惡果不足惜吟策,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望的止。 院中可真熱鬧檩坚,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至赂乐,卻和暖如春薯鳍,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背挨措。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工挖滤, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人浅役。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓斩松,卻偏偏與公主長得像,于是被迫代替她去往敵國和親觉既。 傳聞我的和親對象是個殘疾皇子砸民,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容