成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

SpringMVC入門筆記

gekylin / 2599人閱讀

摘要:簡(jiǎn)介注解用于修飾的方法,根據(jù)的的內(nèi)容,通過(guò)適當(dāng)?shù)霓D(zhuǎn)換為客戶端需要格式的數(shù)據(jù)并且寫入到的數(shù)據(jù)區(qū),從而不通過(guò)視圖解析器直接將數(shù)據(jù)響應(yīng)給客戶端。并且這些解析器都實(shí)現(xiàn)了接口,在接口中有四個(gè)最為主要的接口方法。

SpringMVC 細(xì)節(jié)方面的東西很多,所以在這里做一篇簡(jiǎn)單的 SpringMVC 的筆記記錄,方便以后查看。

Spring MVC是當(dāng)前最優(yōu)秀的MVC框架,自從Spring 2.5版本發(fā)布后,由于支持注解配置,易用性有了大幅度的提高。Spring 3.0更加完善,實(shí)現(xiàn)了對(duì)老牌的MVC框架Struts 2的超越,現(xiàn)在版本已經(jīng)到了Spring5.x了。

一、工程創(chuàng)建 1.添加架包

創(chuàng)建Maven的web工程,添加依賴架包

Maven架包添加 spring-context、spring-webspring-webmvc、log4j

2.web.xml配置

在web.xml中配置DispatcherServlet


  dispatcherServlet
  org.springframework.web.servlet.DispatcherServlet
  
    contextConfigLocation
    classpath:spring-mvc.xml
  
  1



  dispatcherServlet
  /

注意:這里配置的 / 攔截資源配置的是 /,攔截所有除其他 servlet 之外的資源訪問(wèn),包括 jsp、靜態(tài)網(wǎng)頁(yè)、圖片等等。與 /* 不一樣,/* 一般配在攔截器里面,攔截所有資源訪問(wèn)。

3.創(chuàng)建SpringMVC的配置文件

上面配置 DispatcherServlet 里面用到了 contextConfigLocation 配置文件的地址,下面來(lái)創(chuàng)建配置文件。




    
    

    
    

    
    

    
    
        
        
    

    
    

二、@RequestMapping 注解

在對(duì) SpringMVC 進(jìn)行的配置的時(shí)候, 需要我們指定請(qǐng)求與處理方法之間的映射關(guān)系。 指定映射關(guān)系,就需要我們用上 @RequestMapping 注解。
@RequestMapping 是 Spring Web 應(yīng)用程序中最常被用到的注解之一,這個(gè)注解會(huì)將 HTTP 請(qǐng)求映射到控制器(Controller類)的處理方法上。

1.value和method屬性

簡(jiǎn)單例子

@RequestMapping("rm")
@Controller
public class RequestMappingController {

    @RequestMapping(value = {"home", "/", ""}, method = RequestMethod.GET)
    public String goRMHome() {
        System.out.println("訪問(wèn)了 Test RequestMapping 首頁(yè)");
        return "1-rm";
    }
}

最終訪問(wèn)路徑是 .../rm/home,通過(guò)該方法返回視圖名字和SpringMVC視圖解析器加工,最終會(huì)轉(zhuǎn)發(fā)請(qǐng)求到 .../WEB-INF/jsp/1-rm.jsp 頁(yè)面。
如果沒(méi)有類名上面的 @RequestMapping("rm"),則訪問(wèn)路徑為 .../home。
method 指定方法請(qǐng)求類型,取值有 GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE。
value 為數(shù)組字符串,指定訪問(wèn)路徑與方法對(duì)應(yīng),指定的地址可以是URI。URI值可以是中:普通的具體值、包含某變量、包含正則表達(dá)式。

下面以包含某一變量舉例:

@RequestMapping(value = "testPathVariable/{username}", method = RequestMethod.GET)
public String testPathVariable(@PathVariable(value = "username") String name) {
    //參數(shù)部分也可以直接寫成 @PathVariable String username, 省略value, 保證形參名與上面 {} 內(nèi)的名字一致
    //不建議省略
    System.out.println("訪問(wèn)了 Test PathVariable 方法 username: " + name);
    return "success";
}
2.consumes屬性

指定處理請(qǐng)求的提交內(nèi)容類型(Content-Type)

@RequestMapping(value = "testConsumes", method = RequestMethod.POST, consumes = "application/x-www-form-urlencoded")
public String testConsumes() {
    System.out.println("訪問(wèn)了 Test Consumes 方法");
    return "success";
}

如果請(qǐng)求里面的 Content-Type 對(duì)不上會(huì)報(bào)錯(cuò)

3.produces屬性

指定返回的內(nèi)容類型,僅當(dāng)request請(qǐng)求頭中的(Accept)類型中包含該指定類型才返回

其中 */*;q=0.8 表明可以接收任何類型的,權(quán)重系數(shù)0.8表明如果前面幾種類型不能正常接收則使用該項(xiàng)進(jìn)行自動(dòng)分析。

@RequestMapping(value = "testProduces", method = RequestMethod.POST, produces = "text/html")
public String testProduces() {
    return "success";
}
4.params屬性

指定request中必須包含某些參數(shù)值,才讓該方法處理

JSP頁(yè)面請(qǐng)求

用戶名:
密 碼:

Controller 里面對(duì)應(yīng)的請(qǐng)求方法

@RequestMapping(value = "testParams", method = RequestMethod.POST, params = {"username!=Tom", "password"})
public String testParams() {
    return "success";
}

params = {"username!=Tom", "password"} 表示請(qǐng)求參數(shù)里面 username !=Tom 且有包含 password,二者有一個(gè)不滿足則會(huì)報(bào)錯(cuò)

5.headers屬性

指定 request 中必須包含某些指定的 header 值,才能讓該方法處理請(qǐng)求

@RequestMapping(value = "testHeaders", method = RequestMethod.GET, headers = "Accept-Language=zh-CN,zh;q=0.9")
public String testHeaders() {
    return "success";
}

如果跟設(shè)定頭里面對(duì)不上會(huì)報(bào)404錯(cuò)誤

三、@RequestParam注解

請(qǐng)求

單參數(shù) GET 請(qǐng)求方式
1.省略注解

表單元素的name名字和控制器里的方法的形參名一致,此時(shí)可以省略 @RequestParam 注解

@RequestMapping(value = "testGetOneParam", method = RequestMethod.GET)
public String testGetOneParam(String username) {
    System.out.println("訪問(wèn)了 單參數(shù) Get 請(qǐng)求方法 username: " + username);
    return "success";
}
2.不省略注解

示例

@RequestMapping(value = "testPostOneParam", method = RequestMethod.POST)
public String testPostOneParam(@RequestParam String username) {
    System.out.println("username: " + name);
    return "success";
}

參數(shù)名字不一致時(shí)

@RequestMapping(value = "testPostOneParam", method = RequestMethod.POST)
public String testPostOneParam(@RequestParam(value = "username", required = false, defaultValue = "") String name) {
    System.out.println("username: " + name);
    return "success";
}

value 屬性指定傳過(guò)來(lái)的參數(shù)名,跟方法里的形參名字對(duì)應(yīng)上
required 指定該參數(shù)是否是必須攜帶的
defaultValue 沒(méi)有或者為 null 時(shí),指定默認(rèn)值

注:省略和不省略 @RequestParam 注解,最終SpringMVC內(nèi)部都是使用 RequestParamMethodArgumentResolver 參數(shù)解析器進(jìn)行參數(shù)解析的。如果省略 @RequestParam 注解或省略 @RequestParam 注解的 value 屬性則最終則以形參的名字作為 keyHttpServletRequest 中取值。

四、@RequestHeader 和 @CookieValue 注解

@RequestHeader 注解:可以把 Request 請(qǐng)求 header 部分的值綁定到方法的參數(shù)上

@RequestMapping(value = "rh")
@Controller
public class RequestHeaderController {

    @RequestMapping(value = "testRHAccept", method = RequestMethod.GET)
    public String testRHAccept(@RequestHeader(value = "Accept") String accept) {
        System.out.println(accept);
        return "success";
    }

    @RequestMapping(value = "testRHAcceptEncoding", method = RequestMethod.GET)
    public String testRHAcceptEncoding(@RequestHeader(value = "Accept-Encoding") String acceptEncoding) {
        System.out.println(acceptEncoding);
        return "success";
    }
}

@CookieValue 注解:可以把Request header中關(guān)于cookie的值綁定到方法的參數(shù)上

@RequestMapping(value = "cv")
@Controller
public class CookieValueController {
    @RequestMapping(value = "testGetCookieValue", method = RequestMethod.GET)
    public String testGetCookieValue(@CookieValue(value = "JSESSIONID") String cookie) {
        System.out.println("獲取到Cookie里面 JSESSIONID 的值 " + cookie);
        return "success";
    }
}
五、數(shù)據(jù)結(jié)果封裝 ModelAndView & ModelMap & Map & Model

SpringMVC 為了方便數(shù)據(jù)封裝和處理,提供了以下幾種方案,最終會(huì)將封裝到模型里面的數(shù)據(jù)全都通過(guò) request.setAttribute(name, value) 添加request請(qǐng)求域中。

1.ModelAndView

使用 ModelAndView 類用來(lái)存儲(chǔ)處理完后的結(jié)果數(shù)據(jù),以及顯示該數(shù)據(jù)的視圖。從名字上看 ModelAndView 中的 Model 代表模型,View 代表視圖。model ModelMap 的類型,而 ModelMap 又是 LinkedHashMap 的子類,view 包含了一些視圖信息。

@RequestMapping(value = "testReturnModelAndView", method = RequestMethod.GET)
public ModelAndView testReturnModelAndView() {

    Student s1 = new Student(1, "Tom", 13, new Date());
    Student s2 = new Student(2, "Jerry", 14, new Date());

    List list = new ArrayList<>();
    list.add(s1); list.add(s2);

    HashMap map = new HashMap<>();
    map.put("s1", s1); map.put("s2", s2);

    ModelAndView mv = new ModelAndView();
    mv.addObject("s1", s1);
    mv.addObject("s2", s2);

    mv.addObject("list", list);
    mv.addObject("map", map);
    mv.setViewName("5-m&v-success");
    return mv;
}
2.ModelMap & Map & Model

最終也是將封裝的數(shù)據(jù)和返回視圖名字封裝成 ModelAndView對(duì)象

@RequestMapping(value = "testMapParam", method = RequestMethod.GET)
public String testMapParam(Map paramMap) {
    ...
    paramMap.put("s1", s1);
    paramMap.put("s2", s2);

    paramMap.put("list", list);
    paramMap.put("map", map);
    return "5-m&v-success";
}

@RequestMapping(value = "testModelParam", method = RequestMethod.GET)
public String testModelParam(Model model) {
    ...
    model.addAttribute("s1", s1);
    model.addAttribute("s2", s2);

    model.addAttribute("list", list);
    model.addAttribute("map", map);
    return "5-m&v-success";
}

@RequestMapping(value = "testModelMapParam", method = RequestMethod.GET)
public String testModelMapParam(ModelMap modelMap) {
    ...
    modelMap.addAttribute("s1", s1);
    modelMap.addAttribute("s2", s2);

    modelMap.addAttribute("list",list);
    modelMap.addAttribute("map", map);
    return "5-m&v-success";
}
3.JSP頁(yè)面提取數(shù)據(jù)
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" isELIgnored="false" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>



    
        

單個(gè)數(shù)據(jù)封裝

s1
姓名${s1.name}
年齡${s1.age}
生日${s1.birthday.toString()}
s2
姓名${s2.name}
年齡${s2.age}
生日${s2.birthday.toString()}

List數(shù)據(jù)封裝

${status.count}
姓名${s.name}
年齡${s.age}
生日${s.birthday.toString()}

Map數(shù)據(jù)封裝

${node.key}
姓名${node.value.name}
年齡${node.value.age}
生日${node.value.birthday.toString()}
六、@SessionAttributes

如果我們希望在多個(gè)請(qǐng)求之間共用某個(gè)模型屬性數(shù)據(jù),則可以在控制器類上標(biāo)注一個(gè) @SessionAttributes,SpringMVC 將把模型中對(duì)應(yīng)的屬性暫存到 HttpSession 的域中。

使用方法:
@SessionAttributes(value={"xxx"}, types={xxxx.class})
value:是通過(guò)鍵來(lái)指定放入HttpSession 的域中的值;
types:是通過(guò)類型指定放入HttpSession 的域中的值;

@SessionAttributes(types=Student.class)
這個(gè)注解會(huì)將類中所有放入 Request 域中的 Student 對(duì)象同時(shí)放進(jìn) HttpSession 的域空間中。

可以添加多個(gè)屬性
@SessionAttributes(value={“s1”, “s2”})
@SessionAttributes(types={User.class, Grade.class})

可以混合使用
@SessionAttributes(value={“s1”, “s2”},types={Grade.class})

示例

//@SessionAttributes(value = {"s1", "s2"})
@SessionAttributes(types = Student.class)
@RequestMapping(value = "sa")
@Controller
public class SessionAttributesController {

    @RequestMapping(value = "testSA", method = RequestMethod.GET)
    public String testSessionAttributes(Model model) {
        Student s1 = new Student(1, "Tom", 13, new Date());
        Student s2 = new Student(2, "Jerry", 13, new Date());

        model.addAttribute("s1", s1);
        model.addAttribute("s2", s2);
        return "6-sa-success";
    }
}

JSP 頁(yè)面提取數(shù)據(jù)

<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" isELIgnored="false" %>


    request s1 : ${requestScope.get("s1")}

request s2 : ${requestScope.get("s2")}

session s1 : ${sessionScope.get("s1")}

session s2 : ${sessionScope.get("s2")}

七、@ModelAttribute

該注解平時(shí)使用的比較多,不僅可以寫在方法上面也可以寫在參數(shù)前面。

1.寫在方法上面

在同一個(gè)控制器中,標(biāo)注了@ModelAttribute 的方法實(shí)際上會(huì)在 @RequestMapping 注解方法之前被調(diào)用。

標(biāo)注了@ModelAttribute 的方法能接受與@RequestMapping 標(biāo)注相同的參數(shù)類型,只不過(guò)不能直接被映射到具體的請(qǐng)求上。

標(biāo)注在方法上的 @ModelAttribute 說(shuō)明方法一般是用于添加一個(gè)或多個(gè)屬性到 model 上。

模擬請(qǐng)求

模擬請(qǐng)求
① 省略 value 屬性值手動(dòng)加入屬性
@ModelAttribute
public void modelAttributeMethod1(ModelMap modelMap) {
    Person person = new Person("超哥哥 1 號(hào)", 12);
    modelMap.addAttribute("person1", person);
}

@RequestMapping(value = "testModelAttribute", method = RequestMethod.GET)
public String testModelAttribute(ModelMap modelMap) {
    modelMap.forEach((key, value) -> {
        System.out.println(key + " = " + value);
        //person1 = Person{name="超哥哥 1 號(hào)", age=12}
    });
    return "success";
}

可以看出手動(dòng)加入 model 里面屬性成功,key 為自定義的字符串。

② 省略 value 屬性值自動(dòng)加入屬性
@ModelAttribute
public Person modelAttributeMethod2() {
    return new Person("超哥哥 2 號(hào)", 12);
}

@RequestMapping(value = "testModelAttribute", method = RequestMethod.GET)
public String testModelAttribute(ModelMap modelMap) {
    modelMap.forEach((key, value) -> {
        System.out.println(key + " = " + value);
        //person = Person{name="超哥哥 2 號(hào)", age=12}
    });
    return "success";
}

可以看出 @ModelAttribute 修飾的方法沒(méi)有指定 value 屬性時(shí),讓其自動(dòng)加入的 key 是以添加類的類名首字母小寫。

③ 指明 value 屬性值自動(dòng)加入屬性
@ModelAttribute(value = "person3")
public Person modelAttributeMethod3() {
    return new Person("超哥哥 3 號(hào)", 13);
}

@RequestMapping(value = "testModelAttribute", method = RequestMethod.GET)
public String testModelAttribute(ModelMap modelMap) {
    modelMap.forEach((key, value) -> {
        System.out.println(key + " = " + value);
        //person3 = Person{name="超哥哥 3 號(hào)", age=13}
    });
    return "success";
}

從上面可以看出 @ModelAttribute 修飾的方法有指定 value 屬性時(shí),讓其自動(dòng)加入的 key 就是自定的 value 屬性的值。

2.寫在參數(shù)前面

標(biāo)注在方法參數(shù)前的 @ModelAttribute 說(shuō)明了該方法參數(shù)的值將由 model 中取得,如果 model 中找不到,那么該參數(shù)會(huì)先被實(shí)例化,然后被添加到 model 中。在 model 中存在以后,將請(qǐng)求中所有名稱匹配的參數(shù)都填充到該參數(shù)對(duì)象上。

模擬請(qǐng)求

模擬請(qǐng)求
① 省略 value 屬性值自動(dòng)匹配或創(chuàng)建
@RequestMapping(value = "testModelAttribute", method = RequestMethod.GET)
public String testModelAttribute(@ModelAttribute Person person) {
    System.out.println(person);
    //Person{name="null", age=13}
    return "success";
}

注:在執(zhí)行 testModelAttribute(..) 方法時(shí),因?yàn)閰?shù)屬性是一個(gè) Person 類對(duì)象,那么他先從 model 里面找(沒(méi)有指明 value 屬性值,則以該類名首字母小寫為 key),發(fā)現(xiàn)找不到便創(chuàng)建一個(gè),把請(qǐng)求里面的參數(shù)賦值到該創(chuàng)建對(duì)象上,找到了則用請(qǐng)求里面的參數(shù)更新該對(duì)象。

② 指定 value 屬性值匹配或創(chuàng)建
@ModelAttribute(value = "p")
public Person modelAttributeMethod3(@RequestParam Integer age) {
    return new Person("超哥哥 3 號(hào)", age);
}

@RequestMapping(value = "testModelAttribute", method = RequestMethod.GET)
public String testModelAttribute(@ModelAttribute(value = "p") Person person) {
    System.out.println(person);
    //Person{name="超哥哥 3 號(hào)", age=13}
    return "success";
}

注:在執(zhí)行 testModelAttribute(..) 方法時(shí),因?yàn)閰?shù)屬性是一個(gè) Person 類對(duì)象,那么他先從 model 里面找(有指明 value 屬性值,則以 value 屬性值為 key),發(fā)現(xiàn)找不到便創(chuàng)建一個(gè),把請(qǐng)求里面的參數(shù)賦值到該創(chuàng)建對(duì)象上,找到了則用請(qǐng)求里面的參數(shù)更新該對(duì)象。

③ 省略 @ModelAttribute 注解的 POJO 參數(shù)
@ModelAttribute
public Person modelAttributeMethod3(@RequestParam Integer age) {
    return new Person("超哥哥 4 號(hào)", age);
}

@RequestMapping(value = "testModelAttribute", method = RequestMethod.GET)
public String testModelAttribute(Person person) {
    System.out.println(person);
    //Person{name="超哥哥 4 號(hào)", age=13}
    return "success";
}

注:@ModelAttribute 注解修飾的方法,沒(méi)有指定 value 屬性,則自動(dòng)注入到 model 里面的 value 以該對(duì)象類名首字母小寫為 key。在下面 @RequestMapping 修飾的方法 testModelAttribute(..) 參數(shù)時(shí)一個(gè) POJO 對(duì)象,雖前面沒(méi)有注解修飾,但默認(rèn)也會(huì)去匹配 ModelAttributeMethodProcessor 參數(shù)解析器去解析該參數(shù),說(shuō)白了與上面的第一種情況 @ModelAttribute 注解修飾沒(méi)有設(shè)置 value 屬性值是一樣的。

八、在Controller中使用redirect方式處理請(qǐng)求

forword:表示轉(zhuǎn)發(fā)!
redirect:表示重定向!

@RequestMapping(value = "index")
public String index() {
    return "success";
}
@RequestMapping(value = "index")
public String index() {
    return "redirect:success";
}
九、RESTFul 風(fēng)格的 SpringMVC 1.RESTFulController
@RequestMapping(value = "rest")
@Controller
public class RESTFulController {

    @RequestMapping(value = {"home", "/", ""}, method = RequestMethod.GET)
    public String goResetHome() {
        System.out.println("訪問(wèn)了 Rest 風(fēng)格測(cè)試首頁(yè)");
        return "8-rest";
    }

    @RequestMapping(value = "student/{id}", method = RequestMethod.GET)
    public String get(@PathVariable(value = "id") Integer id) {
        System.out.println("get " + id);
        return "success";
    }

    @RequestMapping(value = "student/{id}", method = RequestMethod.POST)
    public String post(@PathVariable(value = "id") Integer id) {
        System.out.println("post " + id);
        return "success";
    }

    @RequestMapping(value = "student/{id}", method = RequestMethod.PUT)
    public String put(@PathVariable(value = "id") Integer id) {
        System.out.println("put " + id);
        return "success";
    }

    @RequestMapping(value = "student/{id}", method = RequestMethod.DELETE)
    public String delete(@PathVariable(value = "id") Integer id) {
        System.out.println("delete " + id);
        return "success";
    }
}
2.web.xml中配置

form表單發(fā)送put和delete請(qǐng)求,需要在web.xml中進(jìn)行如下配置



  hiddenHttpMethodFilter
  org.springframework.web.filter.HiddenHttpMethodFilter


  hiddenHttpMethodFilter
  /*
3.模擬請(qǐng)求
十、@RequestBody 和 @ResponseBody

在SpringMVC的 Controller 中經(jīng)常會(huì)用到 @RequestBody@ResponseBody 這兩個(gè)注解,若想使用這兩個(gè)注解,前提要寫好 標(biāo)簽,他會(huì)幫我們注入接下里解析需要的轉(zhuǎn)換器。

1.@RequestBody

簡(jiǎn)介:
@RequestBody 注解用于修飾 Controller 的方法參數(shù),根據(jù) HTTP Request Header 的 content-Type 的內(nèi)容,通過(guò)適當(dāng)?shù)?HttpMessageConverter 轉(zhuǎn)換為 Java 類。

使用時(shí)機(jī):
當(dāng)提交的數(shù)據(jù)不是普通表單的形式(application/x-www-form-urlcoded、multipart/form-data),而是 JSON 格式(application/json) 或 XML 格式(application/xml)。

使用示例:XML格式數(shù)據(jù)提交

POJO 模型類

@XmlRootElement(name = "person")
public class Person {
    private String name;
    private Integer age;

    public String getName() { return name; }
    @XmlElement
    public void setName(String name) { this.name = name; }
    public Integer getAge() { return age; }
    @XmlElement
    public void setAge(Integer age) { this.age = age; }
}

AJAX 請(qǐng)求

點(diǎn)擊事件

Controller 里對(duì)應(yīng)的方法

@RequestMapping(value = "testRequestBody", method = RequestMethod.POST)
public String testRequestBody(@RequestBody Person person) {
    System.out.println(person);
    //Person{name="Tom", age=13}
    return "success";
}

注:@RequestBody 注解對(duì)于XML請(qǐng)求數(shù)據(jù)的解析,請(qǐng)求方要指定 Content-Type = application/xml;charset=utf-8,服務(wù)器如果要將接收數(shù)據(jù)封裝成 POJO 類,需要在該 POJO 類里面用 @XmlRootElement@XmlElement 注解指明跟標(biāo)簽和子標(biāo)簽,SpringMVC 內(nèi)部最終用到的是自帶的 Jaxb2RootElementHttpMessageConverter 轉(zhuǎn)換器(其實(shí)現(xiàn)了 HttpMessageConverter 接口)。

2.@ResponseBody

簡(jiǎn)介:
@ResponseBody 注解用于修飾 Controller 的方法,根據(jù) HTTP Request Header 的 Accept 的內(nèi)容,通過(guò)適當(dāng)?shù)?HttpMessageConverter 轉(zhuǎn)換為客戶端需要格式的數(shù)據(jù)并且寫入到 Responsebody 數(shù)據(jù)區(qū),從而不通過(guò)視圖解析器直接將數(shù)據(jù)響應(yīng)給客戶端。

使用時(shí)機(jī):
返回的數(shù)據(jù)不是html標(biāo)簽的頁(yè)面,而是其他某種格式的數(shù)據(jù)時(shí)(如json、xml等)使用。

使用示例:XML格式數(shù)據(jù)響應(yīng)

POJO 模型類

@XmlRootElement(name = "person")
public class Person {
    private String name;
    private Integer age;

    public String getName() { return name; }
    @XmlElement
    public void setName(String name) { this.name = name; }
    public Integer getAge() { return age; }
    @XmlElement
    public void setAge(Integer age) { this.age = age; }
}

Controller 里對(duì)應(yīng)的方法

@ResponseBody
@RequestMapping(value = "testRequestBody", method = RequestMethod.POST)
public Person testRequestBody() {
    Person person = new Person("Tom",13);
    return person;
}

AJAX 請(qǐng)求

點(diǎn)擊事件

最終瀏覽器控制臺(tái)輸出

注:@ResponseBody 注解對(duì)于響應(yīng)XML格式數(shù)據(jù)的解析,請(qǐng)求方要指定 Accept = application/xml;charset=utf-8,服務(wù)器如果想將 POJO 類轉(zhuǎn)換成XML格式數(shù)據(jù),需要在該 POJO 類里面用 @XmlRootElement@XmlElement 注解指明跟標(biāo)簽和子標(biāo)簽,SpringMVC 內(nèi)部最終用到的是自帶的 Jaxb2RootElementHttpMessageConverter 轉(zhuǎn)換器(其實(shí)現(xiàn)了 HttpMessageConverter 接口)。

3.原理簡(jiǎn)介

@RequestBody@ResponseBody 注解最終匹配到的參數(shù)解析器和返回值解析器都是 RequestResponseBodyMethodProcessor 對(duì)象,所以該對(duì)象分別實(shí)現(xiàn)了 HandlerMethodArgumentResolverHandlerMethodReturnValueHandler 接口。
在該解析器中有一個(gè) messageConverters 屬性,該屬性是用來(lái)記錄轉(zhuǎn)換器的 List,這些轉(zhuǎn)換器都是在該解析器初始化的時(shí)候 標(biāo)簽幫我們注入的。并且這些解析器都實(shí)現(xiàn)了 HttpMessageConverter 接口,在 HttpMessageConverter 接口中有四個(gè)最為主要的接口方法。

public interface HttpMessageConverter {
    boolean canRead(Class clazz, @Nullable MediaType mediaType);
    T read(Class clazz, HttpInputMessage inputMessage);

    boolean canWrite(Class clazz, @Nullable MediaType mediaType);
    void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage);
}

read 對(duì)應(yīng)請(qǐng)求輸入的轉(zhuǎn)換解析,write 對(duì)應(yīng)響應(yīng)輸出的轉(zhuǎn)換解析。
canRead 根據(jù) Request Header 的 content-Type 的內(nèi)容查看該 HttpMessageConverter 換器是否支持轉(zhuǎn)換,支持則轉(zhuǎn)換為對(duì)應(yīng)的 Java 類綁定到修飾的方法入?yún)⑸稀?br>canWrite 根據(jù) Request Headers 里面的 Accept 的內(nèi)容查看該 HttpMessageConverter 換器是否支持轉(zhuǎn)換,支持則轉(zhuǎn)換成指定格式后,寫入到 Response 對(duì)象的 body 數(shù)據(jù)區(qū)。

對(duì)應(yīng)流程圖如下

十一、解析和返回 Json 數(shù)據(jù) 1.支持架包導(dǎo)入

首先需要導(dǎo)入 JSON 支持架包并且注入轉(zhuǎn)換器


  com.fasterxml.jackson.core
  jackson-databind
  2.9.6

jackson-databind-2.9.6.jar 架包依賴于 jackson-annotations-2.9.0.jarjackson-core-2.9.6.jar,所以省略了依賴架包的手動(dòng)導(dǎo)入。

同時(shí)要寫好 標(biāo)簽,其會(huì)幫我們注入對(duì)應(yīng)的JSON數(shù)據(jù)轉(zhuǎn)換器。

2.代碼示例

需要封裝的 POJO

public class Person {
    private String name;
    private Integer age;
}

Controller中對(duì)應(yīng)的請(qǐng)求方法

@ResponseBody
@RequestMapping(value = "testRequestBody", method = RequestMethod.POST)
public Person testRequestBody(@RequestBody Person person) {
    System.out.println(person);
    return person;
}

注:參數(shù)用 @RequestBody 修飾意思是將請(qǐng)求的JSON數(shù)據(jù)用合適的轉(zhuǎn)換器,轉(zhuǎn)換成 Java 類。@ResponseBody 注解是將返回的數(shù)據(jù)通過(guò)合適的轉(zhuǎn)換器轉(zhuǎn)換成客戶端想要的樣子并返回,在這里是將請(qǐng)求解析的 Person 對(duì)象轉(zhuǎn)換成JOSN格式數(shù)據(jù)并返回。

AJAX 請(qǐng)求

點(diǎn)擊事件

注:① 發(fā)送的數(shù)據(jù)要是JSON格式(也就是 data 屬性的數(shù)據(jù)是JSON格式);② 指明請(qǐng)求數(shù)據(jù)為JSON格式(contentType: "application/json;charset=utf-8");③ 指明接收數(shù)據(jù)為JSON格式(headers: { Accept: "application/json;charset=utf-8" })。

3. 原理簡(jiǎn)介

最終使用到的轉(zhuǎn)換器是 jackson 提供的 MappingJackson2HttpMessageConverter,也是在解析器初始化的時(shí)候 標(biāo)簽幫我們注入的。

十二、文件上傳 1.支持架包導(dǎo)入

為了實(shí)現(xiàn)文件上傳,需要導(dǎo)入 commons-fileupload 架包,導(dǎo)入如下



    commons-fileupload
    commons-fileupload
    1.3.3
2.配置MultipartResolver

SpringMVC 上下文中默認(rèn)沒(méi)有裝配 MultipartResolver,因此默認(rèn)情況下其不能處理文件上傳工作。如果想使用SpringMVC的文件上傳功能,則需要在上下文中配置 MultipartResolver。在SpringMVC配置文件中進(jìn)行如下配置


    
    
    
    

注:這里一定要設(shè)置 id,并且值必須是 multipartResolver,下面的簡(jiǎn)單原理會(huì)解釋。

3.代碼示例

Controller 中對(duì)應(yīng)的方法

@RequestMapping(value = "upload", method = RequestMethod.POST)
public String testUpload(@RequestParam(value = "file") MultipartFile multipartFile, HttpServletRequest request) throws Exception {
    if (multipartFile.isEmpty() == false) {
        //multipartFile.getName()   標(biāo)簽名字
        //multipartFile.getOriginalFilename()  上傳文件名字
        //multipartFile.getSize()   上傳文件大小
        //multipartFile.getContentType()    上傳文件類型

        //在 webapp 目錄下面(項(xiàng)目目錄下面) 建立一個(gè) resources 資源文件夾, 用來(lái)存儲(chǔ)上傳的資源文件
        String parent = request.getServletContext().getRealPath("/resources");
        String filename = UUID.randomUUID() + multipartFile.getOriginalFilename();

        File file = new File(parent, filename);
        multipartFile.transferTo(file);
    }
    return "success";
}

JSP頁(yè)面的可變表單請(qǐng)求


4.原理簡(jiǎn)介

DispatcherServlet 初始化的時(shí)候,會(huì)從容器中加載 MultipartResolver 可變表單解析器,從下面源碼中可以看出加載條件就是 idname 為 multipartResolver 的 bean

接著簡(jiǎn)單了解下解析,在 DispatcherServletdoDispatch(..) 方法中檢查該請(qǐng)求是否是可變表單請(qǐng)求,如果是則用加載到緩存的 MultipartResolver 解析器 (這里用到的是注入容器中的 CommonsMultipartResolver 可變表單解析器,其實(shí)現(xiàn)了 MultipartResolver 接口) 將可變請(qǐng)求解析成 MultipartFile 對(duì)象 (這里是 CommonsMultipartFile,其實(shí)現(xiàn)了MultipartFile 接口),放在 HttpServletRequest 對(duì)象中,最終通過(guò)合適的參數(shù)解析器綁定到對(duì)應(yīng)方法的參數(shù)上。

十三、文件下載

SpringMVC提供了一個(gè) ResponseEntity 類型,使用它可以很方便地定義返回的 HttpHeadersHttpStatus。
以下代碼演示文件的下載功能

@RequestMapping(value = "download", method = RequestMethod.GET)
public ResponseEntity testDownload(HttpServletRequest request, @RequestParam String filename) throws Exception {

    String parent = request.getServletContext().getRealPath("/resources");
    File file = new File(parent, filename);

    byte[] body = FileUtils.readFileToByteArray(file);

    String downloadFilename = new String(file.getName().getBytes("utf-8"), "iso-8859-1");

    HttpHeaders headers = new HttpHeaders();
    //設(shè)置文件類型
    headers.add("Content-Disposition", "attchement;filename=" + downloadFilename);

    ResponseEntity responseEntity = new ResponseEntity(body, headers, HttpStatus.OK);
    return responseEntity;
}
十四、攔截器

SpringMVC的處理器攔截器,類似于 Servlet 開發(fā)中的過(guò)濾器 Filter,用于對(duì)處理器進(jìn)行預(yù)處理和后處理。

1.過(guò)濾器與攔截器區(qū)別

過(guò)濾器:依賴于servlet容器,在實(shí)現(xiàn)上基于函數(shù)回調(diào),可以對(duì)幾乎所有請(qǐng)求進(jìn)行過(guò)濾,但是缺點(diǎn)是一個(gè)過(guò)濾器實(shí)例只能在容器初始化時(shí)調(diào)用一次。使用過(guò)濾器的目的是用來(lái)做一些過(guò)濾操作,比如:在過(guò)濾器中修改字符編碼;在過(guò)濾器中修改HttpServletRequest的一些參數(shù),包括:過(guò)濾低俗文字、危險(xiǎn)字符等。

攔截器:依賴于web框架,在實(shí)現(xiàn)上基于Java的反射機(jī)制,屬于面向切面編程(AOP)的一種運(yùn)用。由于攔截器是基于web框架的調(diào)用,因此可以使用Spring的依賴注入(DI)進(jìn)行一些業(yè)務(wù)操作,同時(shí)一個(gè)攔截器實(shí)例在一個(gè) Controller 生命周期之內(nèi)可以多次調(diào)用。

2.攔截器接口

攔截器一個(gè)有3個(gè)回調(diào)方法,而一般的過(guò)濾器Filter才兩個(gè):

preHandle預(yù)處理回調(diào)方法,實(shí)現(xiàn)處理器的預(yù)處理。返回值:true表示繼續(xù)流程(如調(diào)用下一個(gè)攔截器或處理器);false表示流程中斷,不會(huì)繼續(xù)調(diào)用其他的攔截器或處理器,此時(shí)我們需要通過(guò) response 來(lái)產(chǎn)生響應(yīng);

postHandle后處理回調(diào)方法,實(shí)現(xiàn)處理器的后處理(但在渲染視圖之前),此時(shí)我們可以通過(guò) modelAndView(模型和視圖對(duì)象)對(duì)模型數(shù)據(jù)進(jìn)行處理或?qū)σ晥D進(jìn)行處理。

afterCompletion整個(gè)請(qǐng)求處理完畢回調(diào)方法,即在視圖渲染完畢時(shí)回調(diào),如性能監(jiān)控中我們可以在此記錄結(jié)束時(shí)間并輸出消耗時(shí)間,還可以進(jìn)行一些資源清理,類似于 try-catch-finally 中的finally。

3.代碼編寫

有時(shí)候我們可能只需要實(shí)現(xiàn)三個(gè)回調(diào)方法中的某一個(gè),如果實(shí)現(xiàn)HandlerInterceptor 接口的話,三個(gè)方法必須實(shí)現(xiàn),此時(shí) SpringMVC 提供了一個(gè) HandlerInterceptorAdapter 適配器(一種適配器設(shè)計(jì)模式的實(shí)現(xiàn)),允許我們只實(shí)現(xiàn)需要的回調(diào)方法,該適配器內(nèi)部實(shí)現(xiàn)了 HandlerInterceptor 接口。

先寫兩個(gè)攔截器

public class HandlerInterceptor1 extends HandlerInterceptorAdapter {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("HandlerInterceptor1 preHandle");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("HandlerInterceptor1 postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("HandlerInterceptor1 afterCompletion");
    }
}
public class HandlerInterceptor2 extends HandlerInterceptorAdapter {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("HandlerInterceptor2 preHandle");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("HandlerInterceptor2 postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("HandlerInterceptor2 afterCompletion");
    }
}

攔截器的注入


    
    

Controller 方法編寫

@RequestMapping(value = "/hello")
public String testHello() {
    System.out.println("HelloController.testHello");
    return "success";
}

最終輸出看下執(zhí)行順序

HandlerInterceptor1 preHandle
HandlerInterceptor2 preHandle
HelloController.testHello
HandlerInterceptor2 postHandle
HandlerInterceptor1 postHandle
HandlerInterceptor2 afterCompletion
HandlerInterceptor1 afterCompletion
4.運(yùn)行流程圖

5.選擇性攔截注入

有的時(shí)候我們需要攔截器攔截指定的請(qǐng)求,這樣也是可以配置的


    
        
        
        
        
        
    

    
        
        
        
    
十五、異常處理

在SpringMVC中,所有用于處理在請(qǐng)求映射和請(qǐng)求處理過(guò)程中拋出的異常的類,都要實(shí)現(xiàn) HandlerExceptionResolver 接口。
一個(gè)基于SpringMVC的Web應(yīng)用程序中,可以存在多個(gè)實(shí)現(xiàn)了 HandlerExceptionResolver 的異常處理類,他們的執(zhí)行順序是由其 order 的值從小到大來(lái)先后執(zhí)行,直到遇到返回的 ModelAndView 不為空則終斷接下來(lái)的異常解析器的執(zhí)行并返回異常的 ModelAndView 對(duì)象。

標(biāo)簽會(huì)幫我們注入常用的三個(gè)異常解析器:ExceptionHandlerExceptionResolverResponseStatusExceptionResolver、DefaultHandlerExceptionResolver。

但是我們接下來(lái)重點(diǎn)是了解下常用的兩個(gè)異常解析器,分別是:ExceptionHandlerExceptionResolverSimpleMappingExceptionResolver。

1.ExceptionHandlerExceptionResolver

注意 @ExceptionHandler 注解修飾的方法里面,只能自己 newModelAndView 對(duì)象然后裝入需要的注入的值,對(duì)于傳參里面帶的 ModelModelMap 達(dá)不到傳值要求。

① 異常處理方法寫在對(duì)應(yīng)的類里面

這樣只能處理該 Controller 里面的異常

處理該 Controller 里面所有的異常,在沒(méi)有找到指定的異常類對(duì)應(yīng)的處理方法的前提下

@ExceptionHandler
public ModelAndView handlerAllException(Exception e) {
    ModelAndView mv = new ModelAndView();
    mv.addObject("exceptionMsg", e.getMessage());
    mv.setViewName("error");
    System.out.println("HelloController.handlerAllException");
    return mv;
}

處理該 Controller 里面指定類型的異常

@ExceptionHandler(value = {ArithmeticException.class})
public ModelAndView handlerArithmeticException(Exception e) {
    ModelAndView mv = new ModelAndView();
    mv.addObject("exceptionMsg", e.getMessage());
    mv.setViewName("error");
    System.out.println("HelloController.handlerArithmeticException");
    return mv;
}
② 異常處理方法寫在多帶帶的異常處理類里面

這樣可以處理所有 Controller 的異常,而不是針對(duì)單個(gè)的 Controller 類,類上需要用 @ControllerAdvice 注解修飾。

@ControllerAdvice
public class HandlerException {
    @ExceptionHandler
    public ModelAndView handlerAllException(Exception e) {
        ModelAndView mv = new ModelAndView();
        mv.addObject("exceptionMsg", e.getMessage());
        mv.setViewName("error");
        System.out.println("HelloController.handlerAllException");
        return mv;
    }
    @ExceptionHandler(value = {ArithmeticException.class})
    public ModelAndView handlerArithmeticException(Exception e) {
        ModelAndView mv = new ModelAndView();
        mv.addObject("exceptionMsg", e.getMessage());
        mv.setViewName("error");
        System.out.println("HelloController.handlerArithmeticException");
        return mv;
    }
}
2.SimpleMappingExceptionResolver

不用自己寫java類處理異常,直接配置就可以了


    
    
    
        
            error
        
    
十六、整合SpringIOC和SpringMVC

在 web.xml 中配置 contextLoaderListener,并且加入spring的配置文件 applicationContext.xml

這樣可以把 service、dao、事務(wù)、緩存、以及和其它框架的整合放到 spring 的配置文件里面
web.xml 文件配置如下





    
    
        contextConfigLocation
        classpath:applicationContext.xml
    
    
        org.springframework.web.context.ContextLoaderListener
    
    
    
    
        dispatcherServlet
        org.springframework.web.servlet.DispatcherServlet
        
            contextConfigLocation
            classpath:spring-mvc.xml
        
        1
    

    
        dispatcherServlet
        /
    

在 web.xml 中配置 SpringMVC 的 Servlet 和加入 springmvc.xml,這時(shí)兩個(gè)配置文件中掃描的包有重合的時(shí)候出現(xiàn)某些bean會(huì)被初始化2次的問(wèn)題。

解決:在掃描包的子節(jié)點(diǎn)下配置 exclude-filterinclude-filter

SpringMVC 只掃描 @Controller@ControllerAdvice


    
    

Spring排除掃描 @Controller@ControllerAdvice


    
    

注意:Spring 和 SpringMVC 都有一個(gè) IOC 容器,并且Controller 類的 bean 在 SpringMVC 的 IOC 容器中,但是它可以引用 Spring 的 IOC 容器中的 bean 如 service 和 dao 層的 bean,反之則不行,因?yàn)?Spring IOC 容器和 SpringMVC IOC 容器是父子關(guān)系,相當(dāng)于全局變量和局部變量的關(guān)系!

十七、SpringMVC運(yùn)行流程

其他相關(guān)文章

SpringMVC入門筆記
SpringMVC工作原理之處理映射HandlerMapping
SpringMVC工作原理之適配器HandlerAdapter
SpringMVC工作原理之參數(shù)解析
SpringMVC之自定義參數(shù)解析
SpringMVC工作原理之視圖解析及自定義
SpingMVC之標(biāo)簽

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/73032.html

相關(guān)文章

  • SpringMVC入門筆記

    摘要:入門筆記簡(jiǎn)介是一種基于的實(shí)現(xiàn)了設(shè)計(jì)模式的請(qǐng)求驅(qū)動(dòng)類型的輕量級(jí)框架,是系開源項(xiàng)目中的一個(gè),和配合使用。配置在中需要添加使用的和映射規(guī)則。入門較快,而掌握起來(lái)相對(duì)較難。 SpringMVC入門筆記 1. 簡(jiǎn)介 Spring MVC是一種基于Java的實(shí)現(xiàn)了Web MVC設(shè)計(jì)模式的請(qǐng)求驅(qū)動(dòng)類型的輕量級(jí)Web框架 ,是Spring系開源項(xiàng)目中的一個(gè),和IoC配合使用。通過(guò)策略接口,Spring...

    zhaochunqi 評(píng)論0 收藏0
  • Java學(xué)習(xí)路線總結(jié),搬磚工逆襲Java架構(gòu)師(全網(wǎng)最強(qiáng))

    摘要:哪吒社區(qū)技能樹打卡打卡貼函數(shù)式接口簡(jiǎn)介領(lǐng)域優(yōu)質(zhì)創(chuàng)作者哪吒公眾號(hào)作者架構(gòu)師奮斗者掃描主頁(yè)左側(cè)二維碼,加入群聊,一起學(xué)習(xí)一起進(jìn)步歡迎點(diǎn)贊收藏留言前情提要無(wú)意間聽到領(lǐng)導(dǎo)們的談話,現(xiàn)在公司的現(xiàn)狀是碼農(nóng)太多,但能獨(dú)立帶隊(duì)的人太少,簡(jiǎn)而言之,不缺干 ? 哪吒社區(qū)Java技能樹打卡?【打卡貼 day2...

    Scorpion 評(píng)論0 收藏0
  • SpringMVC入門就這么簡(jiǎn)單

    摘要:也就是說(shuō)映射器就是用于處理什么樣的請(qǐng)求提交給處理。這和是一樣的提交參數(shù)的用戶名編號(hào)提交配置處理請(qǐng)求注冊(cè)映射器包框架接收參數(shù)設(shè)置無(wú)參構(gòu)造器,里邊調(diào)用方法,傳入要封裝的對(duì)象這里的對(duì)象就表示已經(jīng)封裝好的了對(duì)象了。 什么是SpringMVC? SpringMVC是Spring家族的一員,Spring是將現(xiàn)在開發(fā)中流行的組件進(jìn)行組合而成的一個(gè)框架!它用在基于MVC的表現(xiàn)層開發(fā),類似于struts...

    SKYZACK 評(píng)論0 收藏0
  • 慕課網(wǎng)_《SpringMVC數(shù)據(jù)綁定入門》學(xué)習(xí)總結(jié)

    摘要:數(shù)據(jù)綁定入門學(xué)習(xí)總結(jié)時(shí)間年月日星期日說(shuō)明本文部分內(nèi)容均來(lái)自慕課網(wǎng)。慕課網(wǎng)教學(xué)示例源碼個(gè)人學(xué)習(xí)源碼第一章課程介紹數(shù)據(jù)綁定入門概述數(shù)據(jù)綁定概念來(lái)自百度百科簡(jiǎn)單綁定是將一個(gè)用戶界面元素控件的屬性綁定到一個(gè)類型對(duì)象實(shí)例上的某個(gè)屬性的方法。 《SpringMVC數(shù)據(jù)綁定入門》學(xué)習(xí)總結(jié) 時(shí)間:2017年2月19日星期日說(shuō)明:本文部分內(nèi)容均來(lái)自慕課網(wǎng)。@慕課網(wǎng):http://www.imooc.co...

    Karrdy 評(píng)論0 收藏0
  • angularjs+springMvc學(xué)習(xí)筆記

    摘要:回調(diào)說(shuō)白了,就是把函數(shù)當(dāng)參數(shù)傳給另一根函數(shù),在另一個(gè)函數(shù)執(zhí)行時(shí)調(diào)用此函數(shù)例如,在下面這段代碼中,上面定義了兩個(gè)函數(shù)和,下面的方法請(qǐng)求成功執(zhí)行,失敗執(zhí)行異步異步的原理我看了網(wǎng)上的一些博客和例子,大都以定時(shí)任務(wù)為例子說(shuō)明,但具體的原理我還是不太 回調(diào) 說(shuō)白了,就是把函數(shù)當(dāng)參數(shù)傳給另一根函數(shù),在另一個(gè)函數(shù)執(zhí)行時(shí)調(diào)用此函數(shù)例如,在下面這段代碼中,上面定義了兩個(gè)函數(shù)success和error,下...

    dreamGong 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<