| |||||||||
日 | 一 | 二 | 三 | 四 | 五 | 六 | |||
---|---|---|---|---|---|---|---|---|---|
27 | 28 | 29 | 30 | 1 | 2 | 3 | |||
4 | 5 | 6 | 7 | 8 | 9 | 10 | |||
11 | 12 | 13 | 14 | 15 | 16 | 17 | |||
18 | 19 | 20 | 21 | 22 | 23 | 24 | |||
25 | 26 | 27 | 28 | 29 | 30 | 31 | |||
1 | 2 | 3 | 4 | 5 | 6 | 7 |
@responsebody表示該方法的返回結(jié)果直接寫入HTTP response body中
一般在異步獲取數(shù)據(jù)時使用,在使用@RequestMapping后,返回值通常解析為跳轉(zhuǎn)路徑,加上@responsebody后返回結(jié)果不會被解析為跳轉(zhuǎn)路徑,而是直接寫入HTTP response body中。比如異步獲取json數(shù)據(jù),加上@responsebody后,會直接返回json數(shù)據(jù)。
4、在以上配置都正確的情況下,我的項目還是不能返回json串。報錯:The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers ()。
今天終于在一個外文網(wǎng)站找到答案,是由于spring版本的問題引起的。我之前一直用的是3.0.0的版本。就是因為這個版本的問題。于是果斷去官網(wǎng)下載3.2版本的,一切正常運行,成功返回json數(shù)據(jù)。
struts和spring整合首先要在Web容器啟動的時候自動裝配ApplicationContext的配置信息,可想而知應(yīng)該在web.xml做相應(yīng)的配置:
[html]
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:applicationContext.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
配置了org.springframework.web.context.ContextLoaderListener后我們就不惜要編寫代碼顯示地實例化ApplicationContext對象了。至于為什么要使用監(jiān)聽是因為web.xml 的加載順序是:context-param -> listener -> filter -> servlet 。如果你是在不想使用監(jiān)聽,或許你可以嘗試下繼承struts2的org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter重寫這個它的init方法在StrutsPrepareAndExecuteFilter過濾器init中實例化ApplicationContext對象加載配置信息,雖然這種方法也可行,但是當(dāng)攔截每個action都會加載一次配置信息,重新實例化了一個新的web容器,不僅浪費了資源也讓spring更加依賴了struts。
1、使用xml方式:
struts2配置
<package name="user" extends="struts-default">
<action name="login" class="userAction">
<result name="success">/success.jsp</result>
<result name="input" type="redirect">/index.jsp</result>
</action>
</package>
spring配置
<bean id="userDao" class="org.han.dao.impl.UserDaoImpl" />
<bean id="biz" class="org.han.service.impl.LoginBizImpl">
<property name="userdao" ref="userDao"/>
</bean>
<bean id="userAction" class="org.han.action.LoginAction" scope="prototype" >
<property name="biz" ref="biz" />
</bean>
注意紅色部分,struts2的action class與對應(yīng)的action bean必須相同,這樣才能由spring管理action;
2、struts2使用零配置方式:
當(dāng)你導(dǎo)入了零配置插件包的時候千萬要注意約定大于配置,還是上面的spring配置,只是不需要struts2配置了。
第一種方式:只需要將Action的className對應(yīng)到spring配置中的bean id就行了
@Action(value = "/login", results = { @Result(name = "success", location = "/success.jsp"),@Result(name="input",location="/index.jsp")},className="userAction")
public String login() throws Exception {
// TODO Auto-generated method stub
User u=biz.login(this.getUser());
if(u!=null){
return SUCCESS;
}
return INPUT;
}
第二種方式:
Action注解不需要className了,將spring配置稍作修改
<bean id="org.han.action.LoginAction" class="org.han.action.LoginAction" scope="prototype" >
<property name="biz" ref="biz" />
</bean>
這樣可以是因為當(dāng)你使用零配置的時候,action的class默認(rèn)是當(dāng)前類的全類名,所以和spring整合的時候剛好使用全類名在spring配置中查找以全類名為id的bean。
3、struts2、spring都使用注解方式:
www.2cto.com
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="org.han.dao.impl,org.han.service.impl,org.han.action"/>
</beans>
<context:component-scan base-package=""/>用此種方式,不需要在配置文件中再配置bean,也不需要再導(dǎo)入上面對應(yīng)的處理bean。也就是說可以不需要在配置文件中使用<context:annotation-config/>了,因為此種方式會自動導(dǎo)入
[java]
@Namespace("/")
@Component(value="userLogin")
@Scope(value="prototype")
public class LoginAction extends ActionSupport {
public LoginAction() {
super();
// TODO Auto-generated constructor stub
System.out.println("action:"+this.hashCode());
}
@Autowired
private ILoginBiz biz;
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Autowired
public void setBiz(ILoginBiz biz) {
this.biz = biz;
}
@Override
@Action(value = "hello", results = { @Result(name = "success", location = "/success.jsp"),@Result(name="input",location="/index.jsp")})
public String execute() throws Exception {
// TODO Auto-generated method stub
System.out.println("biz:"+this.biz.hashCode());
User u=biz.login(this.getUser());
if(u!=null){
return SUCCESS;
}
return INPUT;
}
}
@Component 有一個可選的入?yún)ⅲ糜谥付?Bean 的名稱。一般情況下,Bean 都是 singleton 的,需要注入 Bean 的地方僅需要通過 byType 策略就可以自動注入了,所以大可不必指定 Bean 的名稱。除了提供 @Component 注釋外,還定義了幾個擁有特殊語義的注釋,它們分別是:@Repository、@Service 和 @Controller。在目前的 Spring 版本中,這 3 個注釋和 @Component 是等效的,但是從注釋類的命名上,很容易看出這 3 個注釋分別和持久層、業(yè)務(wù)層和控制層(Web 層)相對應(yīng)。雖然目前這 3 個注釋和 @Component 相比沒有什么新意,但 Spring 將在以后的版本中為它們添加特殊的功能。所以,如果 Web 應(yīng)用程序采用了經(jīng)典的三層分層結(jié)構(gòu)的話,最好在持久層、業(yè)務(wù)層和控制層分別采用 @Repository、@Service 和 @Controller 對分層中的類進行注釋,而用 @Component 對那些比較中立的類進行注釋。
@Scope用于定義Bean的作用范圍。
@Autowired 注釋,它可以對類成員變量、方法及構(gòu)造函數(shù)進行標(biāo)注,完成自動裝配的工作。當(dāng) Spring 容器啟動時,AutowiredAnnotationBeanPostProcessor 將掃描 Spring 容器中所有 Bean,當(dāng)發(fā)現(xiàn) Bean 中擁有 @Autowired 注釋時就找到和其匹配(默認(rèn)按類型匹配)的 Bean,并注入到對應(yīng)的地方中去。所以對成員變量使用 @Autowired 后,您大可將它們的 setter 方法刪除。
@Qualifier(“name”) 中的 name是 Bean 的名稱,所以 @Autowired 和 @Qualifier 結(jié)合使用時,自動注入的策略就從 byType 轉(zhuǎn)變成 byName 了。@Autowired 可以對成員變量、方法以及構(gòu)造函數(shù)進行注釋,而 @Qualifier 的標(biāo)注對象是成員變量、方法入?yún)ⅰ?gòu)造函數(shù)入?yún)ⅰ?/p>
@PostConstruct 和 @PreDestroy:JSR-250 為初始化之后/銷毀之前方法的指定定義了兩個注釋類,這兩個注釋只能應(yīng)用于方法上。標(biāo)注了 @PostConstruct 注釋的方法將在類實例化后調(diào)用,而標(biāo)注了 @PreDestroy 的方法將在類銷毀之前調(diào)用。
通過 <bean> 元素的 init-method/destroy-method 屬性進行配置,都只能為 Bean 指定一個初始化 / 銷毀的方法。但是使用 @PostConstruct 和 @PreDestroy 注釋卻可以指定多個初始化 / 銷毀方法,那些被標(biāo)注 @PostConstruct 或@PreDestroy 注釋的方法都會在初始化 / 銷毀時被執(zhí)行。
更多的關(guān)于注解使用:請看官方文檔
4、總結(jié):
1、注釋配置不一定在先天上優(yōu)于 XML 配置。如果 Bean 的依賴關(guān)系是固定的,(如 Service 使用了哪幾個 DAO 類),這種配置信息不會在部署時發(fā)生調(diào)整,那么注釋配置優(yōu)于 XML 配置;反之如果這種依賴關(guān)系會在部署時發(fā)生調(diào)整,XML 配置顯然又優(yōu)于注釋配置,因為注釋是對 Java 源代碼的調(diào)整,您需要重新改寫源代碼并重新編譯才可以實施調(diào)整。
2、如果 Bean 不是自己編寫的類(如 JdbcTemplate、SessionFactoryBean 等),注釋配置將無法實施,此時 XML 配置是唯一可用的方式。
3、注釋配置往往是類級別的,而 XML 配置則可以表現(xiàn)得更加靈活。比如相比于 @Transaction 事務(wù)注釋,使用 aop/tx 命名空間的事務(wù)配置更加靈活和簡單。
所以在實現(xiàn)應(yīng)用中,我們往往需要同時使用注釋配置和 XML 配置,對于類級別且不會發(fā)生變動的配置可以優(yōu)先考慮注釋配置;而對于那些第三方類以及容易發(fā)生調(diào)整的配置則應(yīng)優(yōu)先考慮使用 XML 配置。Spring 會在具體實施 Bean 創(chuàng)建和 Bean 注入之前將這兩種配置方式的元信息融合在一起。
來自:http://hanyexiaoxiao.iteye.com/blog/410123
1. 使用Spring注解來注入屬性
1.1. 使用注解以前我們是怎樣注入屬性的
類的實現(xiàn):
public class UserManagerImpl implements UserManager { private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; } ... }
配置文件:
<bean id="userManagerImpl" class="com.kedacom.spring.annotation.service.UserManagerImpl"> <property name="userDao" ref="userDao" /> </bean> <bean id="userDao" class="com.kedacom.spring.annotation.persistence.UserDaoImpl"> <property name="sessionFactory" ref="mySessionFactory" /> </bean>
1.2. 引入@Autowired注解(不推薦使用,建議使用@Resource)
類的實現(xiàn)(對成員變量進行標(biāo)注)
public class UserManagerImpl implements UserManager { @Autowired private UserDao userDao; ... }
或者(對方法進行標(biāo)注)
public class UserManagerImpl implements UserManager { private UserDao userDao; @Autowired public void setUserDao(UserDao userDao) { this.userDao = userDao; } ... }
配置文件
<bean id="userManagerImpl" class="com.kedacom.spring.annotation.service.UserManagerImpl" /> <bean id="userDao" class="com.kedacom.spring.annotation.persistence.UserDaoImpl"> <property name="sessionFactory" ref="mySessionFactory" /> </bean>
@Autowired可以對成員變量、方法和構(gòu)造函數(shù)進行標(biāo)注,來完成自動裝配的工作。以上兩種不同實現(xiàn)方式中,@Autowired的標(biāo)注位置不同,它們都會在Spring在初始化userManagerImpl這個bean時,自動裝配userDao這個屬性,區(qū)別是:第一種實現(xiàn)中,Spring會直接將UserDao類型的唯一一個bean賦值給userDao這個成員變量;第二種實現(xiàn)中,Spring會調(diào)用setUserDao方法來將UserDao類型的唯一一個bean裝配到userDao這個屬性。
1.3. 讓@Autowired工作起來
要使@Autowired能夠工作,還需要在配置文件中加入以下代碼
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
1.4. @Qualifier
@Autowired是根據(jù)類型進行自動裝配的。在上面的例子中,如果當(dāng)Spring上下文中存在不止一個UserDao類型的bean時,就會拋出BeanCreationException異常;如果Spring上下文中不存在UserDao類型的bean,也會拋出BeanCreationException異常。我們可以使用@Qualifier配合@Autowired來解決這些問題。
1. 可能存在多個UserDao實例
@Autowired public void setUserDao(@Qualifier("userDao") UserDao userDao) { this.userDao = userDao; }
這樣,Spring會找到id為userDao的bean進行裝配。
2. 可能不存在UserDao實例
@Autowired(required = false) public void setUserDao(UserDao userDao) { this.userDao = userDao; }
1.5. @Resource(JSR-250標(biāo)準(zhǔn)注解,推薦使用它來代替Spring專有的@Autowired注解)
Spring 不但支持自己定義的@Autowired注解,還支持幾個由JSR-250規(guī)范定義的注解,它們分別是@Resource、@PostConstruct以及@PreDestroy。
@Resource的作用相當(dāng)于@Autowired,只不過@Autowired按byType自動注入,而@Resource默認(rèn)按byName自動注入罷了。@Resource有兩個屬性是比較重要的,分別是name和type,Spring將@Resource注解的name屬性解析為bean的名字,而type屬性則解析為bean的類型。所以如果使用name屬性,則使用byName的自動注入策略,而使用type屬性時則使用byType自動注入策略。如果既不指定name也不指定type屬性,這時將通過反射機制使用byName自動注入策略。
@Resource裝配順序
1.6. @PostConstruct(JSR-250)
在方法上加上注解@PostConstruct,這個方法就會在Bean初始化之后被Spring容器執(zhí)行(注:Bean初始化包括,實例化Bean,并裝配Bean的屬性(依賴注入))。
它的一個典型的應(yīng)用場景是,當(dāng)你需要往Bean里注入一個其父類中定義的屬性,而你又無法復(fù)寫父類的屬性或?qū)傩缘膕etter方法時,如:
public class UserDaoImpl extends HibernateDaoSupport implements UserDao { private SessionFactory mySessionFacotry; @Resource public void setMySessionFacotry(SessionFactory sessionFacotry) { this.mySessionFacotry = sessionFacotry; } @PostConstruct public void injectSessionFactory() { super.setSessionFactory(mySessionFacotry); } ... }
這里通過@PostConstruct,為UserDaoImpl的父類里定義的一個sessionFactory私有屬性,注入了我們自己定義的sessionFactory(父類的setSessionFactory方法為final,不可復(fù)寫),之后我們就可以通過調(diào)用super.getSessionFactory()來訪問該屬性了。
1.7. @PreDestroy(JSR-250)
在方法上加上注解@PreDestroy,這個方法就會在Bean初始化之后被Spring容器執(zhí)行。由于我們當(dāng)前還沒有需要用到它的場景,這里不不去演示。其用法同@PostConstruct。
1.8. 使用<context:annotation-config />簡化配置
Spring2.1添加了一個新的context的Schema命名空間,該命名空間對注釋驅(qū)動、屬性文件引入、加載期織入等功能提供了便捷的配置。我們知道注釋本身是不會做任何事情的,它僅提供元數(shù)據(jù)信息。要使元數(shù)據(jù)信息真正起作用,必須讓負(fù)責(zé)處理這些元數(shù)據(jù)的處理器工作起來。
AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor就是處理這些注釋元數(shù)據(jù)的處理器。但是直接在Spring配置文件中定義這些Bean顯得比較笨拙。Spring為我們提供了一種方便的注冊這些BeanPostProcessor的方式,這就是<context:annotation-config />:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <context:annotation-config /> </beans>
<context:annotationconfig />將隱式地向Spring容器注冊AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、 PersistenceAnnotationBeanPostProcessor以及RequiredAnnotationBeanPostProcessor這4個BeanPostProcessor。
2. 使用Spring注解完成Bean的定義
以上我們介紹了通過@Autowired或@Resource來實現(xiàn)在Bean中自動注入的功能,下面我們將介紹如何注解Bean,從而從XML配置文件中完全移除Bean定義的配置。
2.1. @Component(不推薦使用)、@Repository、@Service、@Controller
只需要在對應(yīng)的類上加上一個@Component注解,就將該類定義為一個Bean了:
@Component public class UserDaoImpl extends HibernateDaoSupport implements UserDao { ... }
使用@Component注解定義的Bean,默認(rèn)的名稱(id)是小寫開頭的非限定類名。如這里定義的Bean名稱就是userDaoImpl。你也可以指定Bean的名稱:
@Component("userDao")
@Component是所有受Spring管理組件的通用形式,Spring還提供了更加細化的注解形式:@Repository、@Service、@Controller,它們分別對應(yīng)存儲層Bean,業(yè)務(wù)層Bean,和展示層Bean。目前版本(2.5)中,這些注解與@Component的語義是一樣的,完全通用,在Spring以后的版本中可能會給它們追加更多的語義。所以,我們推薦使用@Repository、@Service、@Controller來替代@Component。
2.2. 使用<context:component-scan />讓Bean定義注解工作起來
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <context:component-scan base-package="com.kedacom.ksoa" /> </beans>
這里,所有通過<bean>元素定義Bean的配置內(nèi)容已經(jīng)被移除,僅需要添加一行<context:component-scan />配置就解決所有問題了——Spring XML配置文件得到了極致的簡化(當(dāng)然配置元數(shù)據(jù)還是需要的,只不過以注釋形式存在罷了)。<context:component-scan />的base-package屬性指定了需要掃描的類包,類包及其遞歸子包中所有的類都會被處理。
<context:component-scan />還允許定義過濾器將基包下的某些類納入或排除。Spring支持以下4種類型的過濾方式:
以正則表達式為例,我列舉一個應(yīng)用實例:
<context:component-scan base-package="com.casheen.spring.annotation"> <context:exclude-filter type="regex" expression="com\.casheen\.spring\.annotation\.web\..*" /> </context:component-scan>
值得注意的是<context:component-scan />配置項不但啟用了對類包進行掃描以實施注釋驅(qū)動Bean定義的功能,同時還啟用了注釋驅(qū)動自動注入的功能(即還隱式地在內(nèi)部注冊了AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor),因此當(dāng)使用<context:component-scan />后,就可以將<context:annotation-config />移除了。
2.3. 使用@Scope來定義Bean的作用范圍
在使用XML定義Bean時,我們可能還需要通過bean的scope屬性來定義一個Bean的作用范圍,我們同樣可以通過@Scope注解來完成這項工作:
@Scope("session") @Component() public class UserSessionBean implements Serializable { ... }
3. 參考
http://kingtai168.iteye.com/blog/244002
http://www.iteye.com/topic/244153
http://static.springframework.org/spring/docs/2.5.x/reference/beans.html#beans-annotation-config
http://static.springframework.org/spring/docs/2.5.x/reference/beans.html#beans-classpath-scanning
警告信息如下:
警告: No configuration found for the specified action: '/myNameSpace/login.action' in namespace: ''. Form action defaulting to 'action' attribute's literal value.
struts.xml配置信息(部分)
<package name="packageName" extends="struts-default" namespace="/myNameSpace">
<action name="login" class="com.jato.srvclink.test.login.LoginAction" method="login">
jsp頁面配置信息(部分)
<s:form action="/myNameSpace/login.action">
思考:沒有在''的namespace中發(fā)現(xiàn)指定的action '/myNameSpace/login.action'
答疑:因為配置的struts2標(biāo)簽并未指定namespace屬性。所以struts2會默認(rèn)從根命名空間"/"搜索action串' /myNameSpace/login.action',如果搜索不到將進入默認(rèn)命名空間''搜索action請求串,在默認(rèn)命名空間中是肯定找不到我們 定義的action的,所以,struts2拋出一個警告信息。
但是為什么我們沒有填寫namespace,我們的請求也可以正常訪問呢?
我們來看一下解析后的html
查看源碼得到的html(部分)
<form id="login" onsubmit="return true;" action="/srvclink/myNameSpace/login.action" method="post">
我們看到form提交的action串是準(zhǔn)確的url請求,action串確實是/srvclin(應(yīng)用根)/myNameSpace(命名空間)/login.action。
命名空間中找不到action定義,并不意味著這個action真的不存在,只是我們的代碼有問題而已。還有一點是我們在jsp頁面的action請求中 手動的加入了.action后綴。事實上struts2會自動追加.action的,因為我們并沒有合法的使用struts2的標(biāo)簽,所以struts2 這里并沒有給我們追加.action,解析后的代碼中存在的.action,完全是我們手動在jsp頁面填寫的,有疑問的網(wǎng)友可以不手動添加查看 html。
我們修改我們的程序代碼
jsp頁面配置信息(部分)修改后加入namespace屬性,修改action屬性值為/login.action
<s:form action="/login.action" namespace="/myNameSpace">
請求頁面后,大家很失望吧?警告依然存在。但是我們看一下警告信息。
警告信息:
警告: No configuration found for the specified action: '/login.action' in namespace: '/myNameSpace'. Form action defaulting to 'action' attribute's literal value.
沒有在'/myNameSpace'的namespace中發(fā)現(xiàn)指定的action '/login.action'
毫無疑問,這里的警告和第一次的警告信息截然不同。我們現(xiàn)在存在命名空間,'/myNameSpace'能夠被struts2檢索到,并不是開始的''。那問題的關(guān)鍵在哪里呢?
在namespace中沒有發(fā)現(xiàn)指定的action '/login.action' ???
我們來看一下struts.xml中的配置:
struts.xml配置信息(部分)
<package name="packageName" extends="struts-default" namespace="/myNameSpace">
<action name="login" class="com.jato.srvclink.test.login.LoginAction" method="login">
是的,我們'/myNameSpace'命名空間下,只有action名字為'login'的定義,并沒有所謂的'/login.action' 定義,所以struts2的警告并未錯。如果大家對這個抱有懷疑,可以修改action的名字'login'為‘/longin.action’
<action name="/login.action" class="com.jato.srvclink.test.login.LoginAction" method="login">
請求頁面時你會發(fā)現(xiàn)不在報警告信息,原因很簡單。因為在命名空間為'myNameSpace'下確實存在命名為'/login.action'的action。
我們再次修改配置文件
jsp頁面配置信息(部分)修改后action屬性值為longin
<s:form action="login" namespace="/myNameSpace">
請求頁面時,我們發(fā)現(xiàn)不再有警告信息了。
如果你有足夠細心,我想你應(yīng)該可以徹底的明白為什么struts2會報警了吧?你也應(yīng)該明白了使用struts2標(biāo)簽action中添加/線后請求反而報錯的原因了。