日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

Ajax 異步交互

SpringMVC 默認用 MAppingJackson2HttpMessageConverter 對 JSON 數據進行轉換,需要加入 Jackson 的包;同時在 spring-mvc.xml 使用 <mvc:annotation-driven />

...
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.8</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.9.8</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.9.0</version>
</dependency>
......<!-- 處理器映射器-處理器適配器。進行了功能的增強:支持 json 的讀寫 -->
<mvc:annotation-driven />
...

@RequestBody

該注解用于 Controller 的方法的形參聲明,當使用 Ajax 提交并指定 contentType 為 JSON 形式時,通過 HttpMessageConverter 接口轉換為對應的 POJO 對象。

srcmainwebappajax.jsp

<%@ page contentType="text/html;charset=UTF-8" language="JAVA" %>
<html>
<head>
    <title>Ajax</title>
</head>
<body>
<%-- ajax 異步交互 --%>
<button id="btn1">ajax 異步提交</button>
<script src="${pageContext.request.contextPath}/js/jquery-3.5.1.js"></script>
<script>
    $("#btn1").click(function () {
        let url = '${pageContext.request.contextPath}/user/ajaxRequest';
        let data = '[{"id":1,"username":"張三"},{"id":2,"username":"李四"}]';
?
        $.ajax({
            type: 'POST',
            url: url,
            data: data,
            contentType: 'application/json;charset=utf-8',
            success: function (resp) {
                alert(JSON.stringify(resp));
            }
        })
    });
</script>
</body>
</html>

在 UserController 中添加方法

@RequestMapping("/ajaxRequest")
public List<User> ajaxRequest(@RequestBody List<User> list){
    System.out.println(list);
}

@ResponseBody

該注解用于將 Controller 的方法返回的對象,通過 HttpMessageConverter 接口轉換為指定格式的數據如:JSON,xml 等,通過 Response 響應給客戶端。

@RequestMapping("/ajaxRequest")
@ResponseBody
public List<User> ajaxRequest(@RequestBody List<User> list){
    System.out.println(list);
    return list;
}

 

RESTful

什么是 RESTful

Restful 是一種軟件架構風格、設計風格,而不是標準,只是提供了一組設計原則和約束條件。主要用于客戶端和服務器交互類的軟件,基于這個風格設計的軟件可以更簡潔,更有層次,更易于實現緩存機制等。

Restful 風格的請求是使用“URL + 請求方式”表示一次請求目的的,HTTP 協議里面四個表示操作方式的動詞如下:

  • GET:讀取(Read)
  • POST:新建(Create)
  • PUT:更新(Update)
  • DELETE:刪除(Delete)

查詢所有:/user/findAll GET /user

根據 ID 查詢:/user/findById?id=3 GET /user/{1}

新增:/user/save POST /user

修改:/user/update PUT /user

刪除:/user/delete?id=3 DELETE /user/{1}

代碼實現

@PathVariable

用來接收 RESTful 風格請求地址中占位符的值。

@RestController

RESTful 風格多用于前后端分離項目開發,前端通過 Ajax 與服務器進行異步交互,我們處理器通常返回的是 JSON 數據所以使用 @RestController 來替代 @Controller 和 @ResponseBody 兩個注解。

/**
 * 沒有 ResponseBody 的話,會把 return 的值作為邏輯視圖進行解析;
 * 帶有 ResponseBody 則直接進行數據的響應 */
@RestController // @RestController = @Controller + @ResponseBody
@RequestMapping("/restful")
public class RestfulController {
?
    /**
     * 根據 id 進行查詢
     */
    @GetMapping("/user/{id}") // @RequestMapping(value = "/user/{id}",method = RequestMethod.GET)
    public String findById(@PathVariable Integer id) {
        // 獲取 restful 編程風格中 url 里面占位符的值
        return "findById: " + id;
    }
?
    /**
     * 新增方法
     * POST 對應的是新增
     */
    @PostMapping("/user") // @RequestMapping(value = "/user",method = RequestMethod.POST)
    public String post(){
        return "post";
    }
?
    /**
     * 更新方法
     * PUT 對應的是更新操作
     */
    @PutMapping("/user")
    public String put(){
        return "put";
    }
?
    /**
     * 刪除方法
     */
    @DeleteMapping("/user/{id}")
    public String delete(@PathVariable Integer id){
        return "delete" + id;
    }
?
}

 

文件上傳

文件上傳三要素

  • 表單項 type="file"
  • 表單的提交方式 method="POST"
  • 表單的 enctype 屬性是多部分表單形式 enctype=“multipart/form-data"
<form action="${pageContext.request.contextPath}/fileupload" method="post" enctype="multipart/form-data">
    名稱:<input type="text" name="username"> <br>
    文件:<input type="file" name="filePic"> <br>
    <input type="submit" value="單文件上傳">
</form>

文件上傳原理

當 form 表單的 enctype 取值為 application/x-www-form-urlencoded 時,form 表單的正文內容格式是: name=value&name=value。

當 form 表單的 enctype 取值為 mutilpart/form-data 時,請求正文內容就變成多部分形式:

當 form 表單修改為多部分表單時,request.getParameter() 將失效。

輸入表單項名稱 username 為 "張人大",上傳文件 filePic 為 "a.txt",其中文件的內容為 "test renda";此時表單的 Request Body 的有效載荷 payload 如下:

-----------------------------17656195882531319514853385408
Content-Disposition: form-data; name="username"
?張人大-----------------------------17656195882531319514853385408
Content-Disposition: form-data; name="filePic"; filename="a.txt"
Content-Type: text/plain?test renda-----------------------------17656195882531319514853385408--

單文件上傳

步驟分析:

  1. 導入 fileupload 和 io 坐標
  2. 配置文件上傳解析器
  3. 編寫文件上傳代碼

導入 fileupload 和 io 坐標

<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.3</version>
</dependency>
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.6</version>

配置文件上傳解析器

spring-mvc.xml

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <!-- 設定文件上傳的最大值為 5 MB = 5*1024*1024 B -->
    <property name="maxUploadSize" value="5242880"/>
    <!-- 設定文件上傳時寫入內存的最大值,如果小于這個參數不會生成臨時文件,默認為 10240 -->
    <property name="maxInMemorySize" value="40960"/>
</bean>

編寫文件上傳代碼

<form action="${pageContext.request.contextPath}/fileupload" method="post" enctype="multipart/form-data">
    名稱:<input type="text" name="username"> <br>
    文件:<input type="file" name="filePic"> <br>
    <input type="submit" value="單文件上傳">
</form>@RequestMapping("/fileupload")
public String fileUpload(String username, MultipartFile filePic) throws IOException {    // 獲取表單的提交參數,完成文件上傳    System.out.println(username);    // 獲取原始的文件上傳名    String originalFilename = filePic.getOriginalFilename();    filePic.transferTo(new File("E:/upload/" + username + "_" + originalFilename));
    // 轉發到成功頁面    return "success";
}

多文件上傳

<form action="${pageContext.request.contextPath}/filesupload" method="post" enctype="multipart/form-data">
    名稱:<input type="text" name="username"> <br>
    文件1:<input type="file" name="filePic"> <br>
    文件2:<input type="file" name="filePic"> <br>
    <input type="submit" value="多文件上傳">
</form>@RequestMapping("/filesupload")
public String filesUpload(String username, MultipartFile[] filePic) throws IOException {    //獲取表單的提交參數,完成文件上傳    System.out.println(username);    // 獲取原始的文件上傳名    for (MultipartFile multipartFile : filePic) {
        String originalFilename = multipartFile.getOriginalFilename();        multipartFile.transferTo(new File("E:/upload/" + username + "_" + originalFilename));
    }    // 轉發到成功頁面    return "success";
}

 

異常處理

異常處理的思路

在 Java 中,對于異常的處理一般有兩種方式:

  • 一種是當前方法捕獲處理(try-catch),這種處理方式會造成業務代碼和異常處理代碼的耦合。
  • 另一種是自己不處理,而是拋給調用者處理(throws),調用者再拋給它的調用者,也就是一直向上拋。在這種方法的基礎上,衍生出了 SpringMVC 的異常處理機制。

系統的 Dao、Service、Controller 出現都通過 throws Exception 向上拋出,最后由 SpringMVC 前端控制器交由異常處理器(HandlerExceptionResolver)進行異常處理:

請求往下傳:客戶端 -> 前端控制器 -> Controller -> Service -> Dao
異常往上拋:Dao -> Service -> Controller -> 前端控制器 -> 異常處理器

自定義異常處理器

步驟分析:

  1. 創建異常處理器類實現 HandlerExceptionResolver
  2. 配置異常處理器
  3. 編寫異常頁面
  4. 測試異常跳轉

創建異常處理器類實現 HandlerExceptionResolver

com.renda.exception.GlobalExceptionResolver

public class GlobalExceptionResolver implements HandlerExceptionResolver {
?    /**
     * @param e 實際拋出的異常對象
     */
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
        // 具體的異常處理:產生異常后,跳轉到一個最終的異常頁面
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("error", e.getMessage());
        modelAndView.setViewName("error");
        return modelAndView;
    }
?
}

配置異常處理器

spring-mvc.xml

<bean id="globalExceptionResolver" class="com.renda.exception.GlobalExceptionResolver"/>

編寫異常頁面

srcmainwebappWEB-INFpageserror.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>ERROR</title>
</head>
<body>
?ERROR:${error}?</body>
</html>

測試異常跳轉

com.renda.controller.ExceptionController

@Controller
public class ExceptionController {
    @RequestMapping("/testException")
    public String testException(){
        int i = 1/0;
        return "success";
    }}

web 的處理異常機制

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>404 Error</title>
</head>
<body>
    Renda: 您請求的資源已經刪除</body>
</html>
?<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>500 Error</title>
</head>
<body>
    Renda: 網絡故障,請稍后再試</body>
</html><!-- 處理 404 異常 -->
<error-page>
    <error-code>404</error-code>
    <location>/404.jsp</location>
</error-page>
<!-- 處理 500 異常 -->
<error-page>
    <error-code>500</error-code>
    <location>/500.jsp</location>
</error-page>

 

攔截器

攔截器(interceptor)的作用

Spring MVC 的攔截器類似于 Servlet 開發中的過濾器 Filter,用于對處理器進行預處理和后處理。

將攔截器按一定的順序聯結成一條鏈,這條鏈稱為攔截器鏈 InterceptorChain。在訪問被攔截的方法或字段時,攔截器鏈中的攔截器就會按其之前定義的順序被調用。攔截器也是 AOP 思想的具體實現。

攔截器和過濾器區別

使用范圍:

filter - 是 servlet 規范中的一部分,任何 Java Web 工程都可以使用 。

interceptor - 是 SpringMVC 框架的一部分,只有使用了 SpringMVC 框架的工程才能用。

攔截范圍:

filter - 在 url-pattern 中配置了 /* 后,可以對所有資源進行過濾攔截。

interceptor - 只會攔截訪問控制器方法,如果訪問的是 JSP、HTML、css、Image、JS 就不會進行攔截。

快速入門

步驟分析:

  1. 創建攔截器類實現 HandlerInterceptor 接口
  2. 配置攔截器
  3. 測試攔截器的攔截效果

創建攔截器類實現 HandlerInterceptor 接口

com.renda.interceptor.MyInterceptor1

public class MyInterceptor1 implements HandlerInterceptor {
    /**
     * 在目標方法執行之前進行攔截
     *
     * @return false:不放行
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle1....");
        return true;
    }?    /**
     * 在目標方法執行之后,視圖對象返回之前,執行的方法
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle1....");
    }?    /**
     * 在流程都執行完成后,執行的方法
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion1....");
    }}

配置攔截器

spring-mvc.jsp

<mvc:interceptors>
    <mvc:interceptor>
        <!-- 對所有 controller 類里面的所有方法都進行攔截 -->
        <mvc:mapping path="/**"/>
        <bean class="com.renda.interceptor.MyInterceptor1"></bean>
    </mvc:interceptor>
</mvc:interceptors>

測試攔截器的攔截效果

編寫 com.renda.controller.TargetController,請求到 controller,跳轉頁面

@Controller
public class TargetController {
    @RequestMapping("/target")
    public String targetMethod() {
        System.out.println("targetMethod executed ...");
        return "success";
    }}

success.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>SUCCESS</title>
</head>
<body>
?    <h3>success... ${username}</h3>
    <% System.out.println("Success...");%>
?</body>
</html>

控制臺輸出結果:

preHandle1....
targetMethod executed ...
postHandle1....
Success...
afterCompletion1....

攔截器鏈

開發中攔截器可以單獨使用,也可以同時使用多個攔截器形成一條攔截器鏈。開發步驟和單個攔截器是一樣的,只不過注冊的時候注冊多個,注意這里注冊的順序就代表攔截器執行的順序。

同上,再編寫一個 MyHandlerInterceptor2 操作:

public class MyInterceptor2 implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle2....");
        return true;
    }?    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle2....");
    }?    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion2...");
    }}

spring-mvc.jsp

<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <bean class="com.renda.interceptor.MyInterceptor1"></bean>
    </mvc:interceptor>
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <bean class="com.renda.interceptor.MyInterceptor2"></bean>
    </mvc:interceptor>
</mvc:interceptors>

控制臺輸出結果:

preHandle1....
preHandle2....
targetMethod executed ...
postHandle2....
postHandle1....
Success...
afterCompletion2...
afterCompletion1....

當MyInterceptor1 的 preHandler 方法返回 true,MyHandlerInterceptor2 的 preHandler 方法返回 false;此時,MyInterceptor1 的 preHandler 方法優先執行并返回 true,即便MyHandlerInterceptor2 的 preHandler 方法返回 false,MyInterceptor1 的 afterCompletion 方法仍然被執行了。控制臺輸出結果:

preHandle1....
preHandle2....
afterCompletion1....

當 MyInterceptor1 的 preHandler 方法返回 false,MyHandlerInterceptor2 的 preHandler 方法返回 true;此時,MyInterceptor1 的 preHandler 方法優先執行并返回 false,方法被攔截,MyHandlerInterceptor2 的 preHandler 方法也無法執行。控制臺輸出結果:

preHandle1....

所以形成攔截器鏈時,當攔截器 1 的 preHandler 方法成功執行并返回 true 后,被它攔截的方法即便被另一個攔截器 2 所攔截并返回了 false,攔截器 1 的afterCompletion 方法仍然會被執行。

源碼解釋:

/**
 * Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
 * Will just invoke afterCompletion for all interceptors whose preHandle invocation
 * has successfully completed and returned true.
 */
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
    throws Exception {
    ...}

 

小結

攔截器中的方法說明:

  • preHandle() - 方法將在請求處理之前進行調用,該方法的返回值是布爾值類型的,當它返回為 false 時,表示請求結束,后續的 Interceptor 和 Controller 都不會再執行;當返回值為 true 時就會繼續調用下一個 Interceptor 的 preHandler 方法
  • postHandle() - 該方法是在當前請求進行處理之后被調用,前提是 preHandler 方法的返回值為 true 時才能被調用,且它會在 DispatcherServlet 進行視圖返回渲染之前被調用,所以可以在這個方法中對 Controller 處理之后的 ModelAndView 對象進行操作
  • afterCompletion() - 該方法在整個請求結束之后,就是在DispatcherServlet 渲染了對應的視圖之后執行,前提是 preHandler 方法的返回值為 true 時才能被調用

想了解更多,歡迎關注我的微信公眾號:Renda_Zhang

分享到:
標簽:SpringMVC
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定