天天看點

SpringMVC Spring常用注解應用

1、@Controller (注入服務)

@Component擴充,被@Controller注解的類表示Web層實作,進而見到該注解就想到Web層實作,使用方式和@Component相同;

在SpringMVC中隻需要使用這個标記一個類是Controller,然後使用@RequestMapping和@RequestParam等一些注解用以定義URL請求和Controller方法之間的映射,這樣的Controller就能被外界通路到。此外,Controller不會直接依賴于HttpServletRequest 和HttpServletResponse 等HttpServlet 對象,他們可以通過Controller的方法參數靈活的擷取到。

舉個例子:

@Controller
public class TestController {
 
    @RequestMapping ( "/showView" )
    public ModelAndView showView() {
       ModelAndView modelAndView = new ModelAndView();
       modelAndView.setViewName( "viewName" );
       modelAndView.addObject( " 需要放到 model 中的屬性名稱 " , " 對應的屬性值,它是一個對象 " );
       return modelAndView;
    }
 
}
           

在上面的例子中,@Controller是标記在類TestController上面的, 是以類TestController就是一個SpringMVC Controller對象。分發處理器會掃描使用了該注解的類的方法,并檢測該方法是否調用了@RequestMapping注解。@Controller隻是定義了一個控制器類,而使用@RequestMapping注解的方法才是真正處理請求的處理器。然後使用@RequestMapping ( “/showView” )标記在Controller方法上,表示當請求/showView.do 的時候通路的是TestController 的showView 方法,該方法傳回了一個包括Model 和View 的ModelAndView 對象。

單單使用@Controller 标記在一個類上還不能真正意義上的說它就是SpringMVC 的一個控制器類,因為這個時候Spring 還不認識它。那麼要如何做Spring 才能認識它呢?這個時候就需要把這個控制器類交給Spring 來管理。

第一種方式是在SpringMVC 的配置檔案中定義MyController 的bean 對象。

第二種方式是在SpringMVC 的配置檔案中告訴Spring 該到哪裡去找标記為@Controller 的Controller 控制器。

< context:component-scan base-package = "com.host.app.web.controller" >
       < context:exclude-filter type = "annotation"
           expression = "org.springframework.stereotype.Service" />
    </ context:component-scan > 
           

**注:**上面 context:exclude-filter 标注的是不掃描 @Service 标注的類

2、@RequestMapping

使用 @RequestMapping 來映射 Request 請求與處理器,通過這個注解可以定義不同的處理器映射規則,即為控制器指定可以處理哪些URL請求。

用@RequestMapping 來映射URL 到控制器類,或者是到Controller 控制器的處理方法上。當@RequestMapping 标記在Controller 類上的時候,裡面使用@RequestMapping 标記的方法的請求位址都是相對于類上的@RequestMapping 而言的;當Controller 類上沒有标記@RequestMapping 注解時,方法上的@RequestMapping 都是絕對路徑。這種絕對路徑和相對路徑所組合成的最終路徑都是相對于根路徑“/ ”而言的。

在上面那個例子中:

這個控制器裡因為TestController 沒有被@RequestMapping 标記,是以當需要通路到裡面使用了@RequestMapping 标記的showView 方法時,就是使用的絕對路徑/showView.do 請求就可以了。

如果改成這樣:

@Controller
@RequestMapping ( "/test" )
public class TestController {
    @RequestMapping ( "/showView" )
    public ModelAndView showView() {
       ModelAndView modelAndView = new ModelAndView();
       modelAndView.setViewName( "viewName" );
       modelAndView.addObject( " 需要放到 model 中的屬性名稱 " , " 對應的屬性值,它是一個對象 " );
       return modelAndView;
    }
 
}
           

這種情況下是在控制器上加了@RequestMapping 注解,是以當需要通路到裡面使用了@RequestMapping 标記的方法showView() 的時候就需要使用showView 方法上@RequestMapping 相對于控制器TestController上@RequestMapping 的位址,即/test/showView.do 。

URL路徑映射:@RequestMapping("/hello"),可以将多個url映射到同一個方法上。

窄化請求映射:

(1)在class上面添加@RequestMapping(url)指定通用請求字首,限制此類下的所有方法請求url必須以請求字首開頭,通過此方法來分類管理url;

(2)在方法名上面再設定請求映射url,即添加@RequestMapping注解在方法名上。return “/WEB-INF/jsp/login.jsp” 調用這個方法,重定向的到指定的jsp頁面或制定的@RequestMapping的請求路徑;

(3)在浏覽器上輸入相應位址,完成通路。

3、@RequestBody

用于讀取http請求的内容(字元串),通過springMVC提供的HttpMessageConverter接口将讀取到的内容轉換為json、xml等格式的資料,再轉換為java對象綁定到Controller類方法的參數上。

簡單點來說,就是把json格式的資料轉換為java對象,就舉個例子來說明:

編寫一個jsp頁面來向背景傳遞json格式的資料(切記是json格式的):

<script>
        jsonData();
        function jsonData()
        {
            $.ajax({
                url:"<%=path%>/user/jsonTest.do",
                contentType:'application/json;charset=utf-8',//設定json格式
                data:'{"username":"張三":"address":"福州"}',
                type:'post',
                success:function(data){
                    alert(data);
                },error:function(error){
                    alert(error);
                }
           })
        }
</script>
           

然後在背景接收一下:

@RequestMapping("/jsonTest.do")
public void jsonTest(@RequestBody User user) throws Exception
{
    System.out.println(user.toString());
}
           

這樣的話,前台的兩個json資料就會自動比對到User這個對象的屬性中了,當然屬性名稱要一樣的。

檢視一下結果:

SpringMVC Spring常用注解應用

可以看到User這個對象中的username和address都已經自動指派好了,這個就是json格式的資料轉java對象了,可以省去我們在背景将json轉成java對象。不過在使用的時候,要注意兩邊的名稱要相同,前台的username要對應java對象中的username這樣才能成功。否則得到如下:

SpringMVC Spring常用注解應用

4、@ResponseBody

含義:

@Responsebody 注解表示該方法的傳回的結果直接寫入 HTTP 響應正文(ResponseBody)中,一般在異步擷取資料時使用,通常是在使用 @RequestMapping 後,傳回值通常解析為跳轉路徑,加上 @Responsebody 後傳回結果不會被解析為跳轉路徑,而是直接寫入HTTP 響應正文中。

作用:

用于将Controller中方法傳回的對象通過适當的HttpMessageConverter轉換為指定格式的資料,如:json、xml等,然後寫入到response對象的body區,通過Response響應給用戶端。需要注意的是,在使用此注解之後不會再走試圖處理器,而是直接将資料寫入到輸入流中,他的效果等同于通過response對象輸出指定格式的資料。

使用時機:

傳回的資料不是html标簽的頁面,而是其他某種格式的資料時(如json、xml等)使用;

舉個例子:

  @RequestMapping("/login")
  @ResponseBody
  public User login(User user){
    return user;
  }
           

User字段是:userName pwd

那麼在前台接收到的資料為:’{“userName”:“xxx”,“pwd”:“xxx”}’

效果等同于如下代碼:

  @RequestMapping("/login")
  public void login(User user, HttpServletResponse response){
    response.getWriter.write(JSONObject.fromObject(user).toString());
  }
           

5、@ModelAttribute

在方法定義上使用該注解: SpringMVC在調用目标處理方法前, 會先逐個調用在方法級上标注了@ModelAttribute的方法;

在方法的入參前使用該注解:可以從隐含對象中擷取隐含的模型資料中擷取對象,再将請求參數 –綁定到對象中,再傳入入參将方法入參對象添加到模型中。

6、@RequestParam

處理簡單類型的綁定,用 @RequestParam 綁定 HttpServletRequest 請求參數到控制器方法參數,即在處理方法入參處使用該注解,可以把請求參數傳遞給請求方法。

@RequestMapping ( "requestParam" )
   public String testRequestParam( @RequestParam(required=false) String name, @RequestParam ( "age" ) int age) {
       return "requestParam" ;
   } 
           

在上面代碼中利用@RequestParam 從HttpServletRequest 中綁定了參數name 到控制器方法參數name ,綁定了參數age 到控制器方法參數age 。當沒有明确指定從request 中取哪個參數時,Spring 在代碼是debug 編譯的情況下會預設取跟方法參數同名的參數,如果不是debug 編譯的就會報錯。此外,當需要從request 中綁定的參數和方法的參數名不相同的時候,也需要在@RequestParam 中明确指出是要綁定哪個參數。在上面的代碼中如果通路 /requestParam.do?name=hello&age=1 則Spring 将會把request請求參數name的值hello賦給對應的處理方法參數name ,把參數age 的值1 賦給對應的處理方法參數age 。

在@RequestParam 中除了指定綁定哪個參數的屬性value之外,還有一個屬性required,它表示所指定的參數是否必須在request 屬性中存在,預設是true,表示必須存在,當不存在時就會報錯。在上面代碼中我們指定了參數name的required的屬性為false ,而沒有指定age 的required 屬性,這時候如果我們通路/requestParam.do而沒有傳遞參數的時候,系統就會抛出異常,因為age 參數是必須存在的,而我們沒有指定。而如果我們通路 /requestParam.do?age=1 的時候就可以正常通路,因為我們傳遞了必須的參數age ,而參數name是非必須的,不傳遞也可以。

value:參數名,即入參的請求參數名字

如:value=“id”,表示将請求的參數區的名字為id的參數的值等待傳入;

require:是否必需,預設是true,表示請求中一定要有相應的參數,否則會報400錯誤。且在每個參數定義前設定。

defaultValue:預設值,表示如果請求中沒有同名參數時的預設值。

通過 require=true 限定參數id必須傳遞,如果不傳遞會報400錯誤;

可以使用defaultValue設定預設值,即使 require=true 也可以不傳遞id參數。

7、@PathVariable 綁定URL占位符到入參。

8、@ExceptionHandler 注解到方法上, 出現異常時會執行該方法。

9、@ControllerAdvice 使一個Controller成為全局的異常處理類, 類中用ExceptinHandler方法注解的方法可以處理所有Controller發生的異常。

10、@Autowired

它可以對類成員變量、方法以及構造函數進行标注,完成自動裝配的工作。自動裝配的意思就是讓Spring從應用上下文中找到對應的bean的引用,并将它們注入到指定的bean。通過@Autowired注解可以完成自動裝配。使用@Autowired 來消除代碼Java代碼裡面的getter/setter與bean屬性中的property。當然,getter看個人需求,如果私有屬性需要對外提供的話,應當予以保留。

隻要對應類型的bean有且隻有一個,則會自動裝配到該屬性上。如果沒有找到對應的bean,應用會抛出對應的異常,如果想避免抛出這個異常,則需要設定@Autowired(required=false)。不過,在應用程式設計中,應該謹慎設定這個屬性,因為這會使得你必須面對NullPointerException的問題。

如果存在多個同一類型的bean,則Spring會抛出異常,表示裝配有歧義,解決辦法有兩個:

(1)通過@Qualifier注解指定需要的bean的ID;

(2)通過@Resource注解指定注入特定ID的bean;

@Autowired 和 @Service("")的配合使用:

執行個體:

@Controller
@RequestMapping("/test")
public class StudentController {
 
    @Autowired
    private StudentService studentService;
 
 
    @RequestMapping("getInfo")
    @ResponseBody
    public int  getInfo(Student student){
        return studentService.insertStu(student);
 
    }
}
           

在Controller中對私有變量用@Autowired标注,因為studentService這個變量是service層接口,是以要找到他的實作類StudentServiceImpl,并在實作類上添加@Service("")的注釋。

@Service("StudentService")
public class StudentServiceImpl implements StudentService {
    @Autowired
    private StudentDao studentDao;
 
    public int insertStu(Student student){
        return studentDao.insertInfo(student);
    }
}
           

如果不添加@Service("")注釋,會報如下錯誤。因為@Autowired 将尋找與之比對的bean來建立(類名)bena,但因為删除接口實作類上@Service("")注解,找不到服務對象,@Autowired自然也就找不到執行個體bean了。

SpringMVC Spring常用注解應用

11、@Override

@Override是僞代碼,表示重寫(當然不寫也可以),不過也有好處:

(1)可以當注釋用,友善閱讀;

         (2)編譯器可以給你驗證@Override下面的方法名是否是你父類中所有的,如果沒有則報錯。
           

例如,你如果沒寫@Override,而你下面的方法名又寫錯了,這時你的編譯器是可以編譯通過的,因為編譯器以為這個方法是你的子類中自己增加的方法。

舉例:在重寫父類的onCreate時,在方法前面加上@Override 系統可以幫你檢查方法的正确性。

@Override

                public void onCreate(Bundle savedInstanceState)

                {…….}
           

這種寫法是正确的,如果你寫成:

@Override

                 public void oncreate(Bundle savedInstanceState)

                 {…….}
           

編譯器會報如下錯誤:

The method oncreate(Bundle) of type HelloWorld must override or implement a supertype method,以確定你正确重寫onCreate方法(因為oncreate應該為onCreate)。
           

而如果你不加@Override,則編譯器将不會檢測出錯誤,而是會認為你為子類定義了一個新方法:oncreate

12、@Transactional

使用時機:

對資料庫的資料進行批量或連表操作時,為了保證資料的一緻性和正确性,則需要添加事務管理機制進行管理;

當對資料庫的資料操作失敗時,事務管理可以很好保證所有的資料 復原 到原來的資料,如果操作成功,則保證所有的需要更新的資料持久化。

復原(Rollback)指的是程式或資料處理錯誤,将程式或資料恢複到上一次正确狀态的行為。

復原包括程式復原和資料復原等類型。

删除由一個或多個部分完成的事務執行的更新。為保證應用程式、資料庫或系統錯誤後還原資料庫的完整性,需要使用復原。

復原泛指程式更新失敗, 傳回上一次正确狀态的行為。

復原與恢複有本質的差別。

更新復原:是指因更新中所發生的意外而自動復原。

使用優點:

(1)開發團隊達成一緻約定,明确标注事務方法的程式設計風格;

(2)保證事務方法的執行時間盡可能短,不要穿插其他網絡操作,RPC/HTTP請求或者剝離到事務方法外部;

(3)不是所有的方法都需要事務,如果隻有一條修改操作、隻讀操作不需要事務控制。

13、@Param

mybatis提供了一個使用注解來參入多個參數的方法,這種方法需要在接口的參數上添加@Param注解。

舉個例子:

/**
     * 更新學生資訊
     * @param student
     * @return
     */
    int updateInfo(@Param("student") Student student);
           

在這個updateInfo的方法中需要傳入多個參數,那麼在進行mybatis配置的時候,沒有辦法同僚配置多個參數,是以需要@Param這個注解來綁定參數對象。student這個參數中包含了三個對象,用@Param來綁定參數并命名為"student"。并且在mapper.xml檔案中調用時,對逐個參數在調用時,要加上 student. 的字首。如下所示:

<update id="updateInfo">
        UPDATE test_student SET name=#{student.name},age=#{student.age} WHERE id=#{student.id}
    </update>
           

注意事項:在使用@Param來注解時,如果使用#{ } 或者 ${ } 的方式都可以,但如果不是用@Param注解時,則必須使用#{ }方式。

14、@Component (把普通pojo執行個體化到spring容器中,相當于配置檔案中的 )

定義Spring管理Bean

在Java配置檔案中有兩個注解值得注意:

@Configuration 表示這個.java檔案是一個配置檔案;

@ComponentScan 表示開啟Component掃描,Spring将會設定該目錄以及子目錄下所有被@Component注解修飾的類。

15、@Configuration

表示這個類是一個spring 配置類,一般這裡面會定義Bean,會把這個類中bean加載到spring容器中。

@Configuration
@ComponentScan(basePackageClasses = {CDPlayer.class, DVDPlayer.class})
public class SoundSystemConfig {
}
           

16、@Bean

在JavaConfig中的屬性注入:

@Bean
public CDPlayer cdPlayer() {
    return new CDPlayer(sgtPeppers());
}
           

看起來是函數調用,實際上不是:由于sgtPeppers()方法被@Bean注解修飾,是以Spring會攔截這個函數調用,并傳回之前已經建立好的bean——確定該SgtPeppers bean為單例。

17、@ComponentScan

@ComponentScan主要就是定義掃描的路徑從中找出辨別了需要裝配的類自動裝配到spring的bean容器中。且這個注解預設會裝配辨別了@Controller,@Service,@Repository,@Component注解的類到spring容器中。

如果不設定basePackage的話,預設會掃描包的所有類,是以最好還是寫上basePackage,減少加載時間。預設掃描**/*.class路徑,比如這個注解在com.wuhulala下面,那麼會掃描這個包下的所有類還有子包的所有類。比如com.wuhulala.service包的應用。

總結@ComponentScan的常用方式:

自定掃描路徑下邊帶有@Controller,@Service,@Repository,@Component注解加入spring容器

通過includeFilters加入掃描路徑下沒有以上注解的類加入spring容器

通過excludeFilters過濾出不用加入spring容器的類

自定義增加了@Component注解的注解方式

18、@Service (注入dao)

用于标注服務層,主要用來進行業務的邏輯處理。@Component擴充,被@Service注解的POJO類表示Service層實作,進而見到該注解就想到Service層實作,使用方式和@Component相同;

19、@Repository (實作dao通路)

用于标注資料通路層,也可以說用于标注資料通路元件,即DAO元件。@Component擴充,被@Repository注解的POJO類表示DAO層實作,進而見到該注解就想到DAO層實作,使用方式和@Component相同;

@RequestParam和@RequestBody的差別

@RequestParam

A) 常用來處理簡單類型的綁定,通過Request.getParameter() 擷取的String可直接轉換為簡單類型的情況( 由String到 簡單類型的轉換操作由ConversionService配置的轉換器來完成);因為使用request.getParameter()方式擷取參數,是以可以處理get 方式中queryString的值,也可以處理post方式中 body data的值。

B)用來處理Content-Type: 為 application/x-www-form-urlencoded編碼的内容,送出方式GET、POST。(不設定這個屬性,好像這就是預設值)

C) 該注解有兩個屬性: value、required; value用來指定要傳入值的id名稱,required用來訓示參數是否必須綁定。

在方法參數裡面如是:

public WebResponse findReleventPolicyPage(@RequestParam("pageSize") Integer pageSize,
                                           @RequestParam("pageNum") Integer pageNum,
                                           @RequestParam("type") Integer type){}
           

@RequestBody

處理HttpEntity傳遞過來的資料,一般用來處理非Content-Type: application/x-www-form-urlencoded編碼格式的資料。

GET請求中,因為沒有HttpEntity,是以@RequestBody并不适用。

POST請求中,通過HttpEntity傳遞的參數,必須要在請求頭中聲明資料的類型Content-Type,SpringMVC通過使用HandlerAdapter 配置的HttpMessageConverters來解析HttpEntity中的資料,然後綁定到相應的bean上。

用于将Controller中方法傳回的對象,通過适當的HttpMessageConverter轉換為指定格式的資料,如:json、xml等,然後通過Response響應給用戶端。

在方法參數裡面如是:

@RequestMapping("/json_test")
// 響應json資料,把pojo對象轉換成json資料并響應
@ResponseBody
public Items jsonTest (@RequestBody Items items){  // 接受json資料并轉換成pojo對象
    return items;
}
           

總結

在GET請求中,不能使用@RequestBody。

在POST請求,可以使用@RequestBody和@RequestParam,但是如果使用@RequestBody,對于參數轉化的配置必須統一。

舉個例子,在SpringMVC配置了HttpMessageConverters處理棧中,指定json轉化的格式,如Date轉成‘yyyy-MM-dd’,則參數接收對象包含的字段如果是Date類型,就隻能讓用戶端傳遞年月日的格式,不能傳時分秒。因為不同的接口,它的參數可能對時間參數有不同的格式要求,是以這樣做會讓用戶端調用同僚對參數的格式有點困惑,是以說擴充性不高。

如果使用@RequestParam來接受參數,可以在接受參數的model中設定@DateFormat指定所需要接受時間參數的格式。

另外,使用@RequestBody接受的參數是不會被Servlet轉化統一放在request對象的Param參數集中,@RequestParam是可以的。

綜上所述,一般情況下,推薦使用@RequestParam注解來接受Http請求參數。