配置SSH的一种实践方法(Spring,Struts2,Hibernate)
近来做了一个小项目,用到了SSH,自己配了下,记录下怕以后忘了。
第一步当然下载建工程下JAR包,我用MAVEN,个人觉得比较方便。贴下我用的版本。
<spring.version>3.1.1.RELEASE</spring.version> <struts2.version>2.3.12</struts2.version> <hibernate.version>4.1.0.Final</hibernate.version>
工程好了,就配相关的东西了。
STRUTS2:
其实主要是struts.xml的配置。具体可以看代码。我就写点配的时候记得比较清楚的。
1. Action,Convention配置。
Convention就是让我们可以少写点代码,但是要配点规则上去,大体意思是告诉STRUTS2去那里找JSP,去那找ACTION.
a. 确保你打开了struts2扫描
<constant name="struts.convention.action.disableScanning" value="false"/>
b.告诉strus2扫描那个包
<constant name="struts.convention.package.locators.basePackage" value="com.demo.action"/>
c. 如果要踢出一些不想扫描的包
<constant name="struts.convention.exclude.packages" value="org.apache.struts.*,org.apache.struts2.*,org.springframework.web.struts.*,org.springframework.web.struts2.*,org.hibernate.*"/>
d. 如果你用JOBSS6,有时候你会有点伤,都照网上的配了,就是不OK,怎么办。也许下面的配置对你有用。
<constant name="struts.convention.action.fileProtocols" value="jar,vfs,vfsfile,vfszip,"/> <bean type="org.apache.struts2.convention.ActionConfigBuilder" name="myActionConfigBuilder" class="com.demo.utils.MyActionConfigBuilder"/> <constant name="struts.convention.actionConfigBuilder" value="myActionConfigBuilder"/>
就是JBOOS用的vfs,还有在扫描的时候好像有点问题。不知道新的解决这个问题没有。当时要写一个actionconfigbuild.有兴趣可看源代码。
e.Struts2里要配个package.
<package name="basic-package" extends="tiles-default,json-default" namespace="/"> </package>
因为项目主用到tiles和json这两种类型的result,所以继承一下。
f. 上ACTION代码了,终于
我一般习惯写一个基类,让他类继承,也好方便我以后控制
public class BasicAction extends ActionSupport
然后再所有action都继承这个
@Controller @Scope(BeanDefinition.SCOPE_PROTOTYPE) @Namespace(BasicAction.BASE_NAME_SPACE) public class ProductAction extends BasicAction {
@Controller是spring一个annoation,我在这里先写上,因为用了spring ioc,后面配的时候再会说到。
@Scope(BeanDefinition.SCOPE_PROTOTYPE)这个一定要,因为spinrg默认是对所有bean是单例的, 加个这个就是每个都是一个新的实体。
@Namespace(BasicAction.BASE_NAME_SPACE)我action放在子包里面所以要加这个,不然URL会变成sub-package-name/action-name.
写个action:
@Action(value = "index", results = {@Result(name = SUCCESS, type = "tiles", location = ".createProduct")}) public String iniProC() throws Exception { return SUCCESS; }
2. Tiles 配置:
上面在家可以看到type是tiles,对了,接下来配tiles.主要是tiles.xml
Tiles主要解决很多网站会很好的分成上中下三块,每次action会有不同的组和,通过一个XML可以很好的把相关的JSP关连起来。
定一个基本的模板。 <definition name=".bodyCenter" template="/jsp/layout/layoutOfBody.jsp"> <put-attribute name="header" value="/jsp/layout/header.jsp"/> <put-attribute name="contentHeader" value="/jsp/layout/userheader.jsp"/> <put-attribute name="bottom" value="/jsp/layout/footer.jsp"/> </definition> 有时要一个简单的模板: <definition name=".simple" extends=".bodyCenter"> <put-attribute name="header" value=""/> <put-attribute name="contentHeader" value=""/> <put-attribute name="bottom" value=""/> </definition> 具体实现: <definition name=".createProduct" extends=".simple"> <put-attribute name="contentBody" value="/jsp/demo/product/create.jsp"/> </definition>
上代码吧,我还是觉得代码比文档更适合用于CODER之间的交流
3. 验证
Struts2分客户端和服务端的。
a. 服务端:
服务端验证就是提交到服务器了再验证,也有两种,一种直接写个方法,struts2会根据名子的规则在调用具体方法之前调用验证方法。比方说你要给一个叫save的ACTION方法加验证,你定义validateSave方法就OK,有ERROR就加到addFieldError("password", "两次密码不一致");这个方法就不细说了。
当然也可以用XML和annotation 我觉是太多annotation在CLASS也不太好看,我就选择了XML
方法就是在类下面加一个这样的XML:
actionName-methodName-validation.xml
里面写你要验证的东东:
<validators> <field name=" user.nickName"> <field-validator type="required"> <message key="user.nickname"></message> </field-validator> </field> </validators>
b.再说一下JS客户端的配法吧
<constant name="struts.ui.theme" value="simple"/>
想用客户端验证,一定不能用simple.请用其他的主题。比方说css_xhtml。因为struts要包一下input框才好后面加error message.但这功能很容易导致UI变开,我后来没用了。要是有CSS高手可能写一个一变开的主题那还是比较好的。比方说error message可以变成一个气泡谈出来之类了.总之大家慎用。
还要加个<s:head />,因为是JS验证嘛,这里面有好多JS会include
4. 国际化
a. 文字:我想大家从资源文件读就OK了,一般问题不大,如果在JAVA里面也有相应的方法可以读取
b. 时间时区:这个会比较坑爹一点,主要看你怎么设计了,我当时只有一台应用服务器,所以我使用的方法是,把服务器改成UTC,这样就不会有跨天的问题,session中保存一下用户的时区,每次显示或上传的时候都会根据这个时区做相应用的改变,这样整个容器里都UTC了,再也不用时区的问题心烦了
显示:
<tag> <description><![CDATA[Render a formatted date.]]></description> <name>date</name> <tag-class>my.utils.CalenderTag</tag-class> <body-content>empty</body-content> <attribute> <description><![CDATA[Date or DateTime format pattern]]></description> <name>format</name> <required>false</required> <rtexprvalue>false</rtexprvalue> </attribute> <attribute> <description><![CDATA[Deprecated. Use 'var' instead]]></description> <name>id</name> <required>false</required> <rtexprvalue>false</rtexprvalue> </attribute> <attribute> <description><![CDATA[The date value to format]]></description> <name>name</name> <required>true</required> <rtexprvalue>false</rtexprvalue> </attribute> <attribute> <description><![CDATA[Whether to print out the date nicely]]></description> <name>nice</name> <required>false</required> <rtexprvalue>false</rtexprvalue> </attribute> <attribute> <description><![CDATA[The specific timezone in which to format the date]]></description> <name>timezone</name> <required>false</required> <rtexprvalue>false</rtexprvalue> </attribute> <attribute> <description><![CDATA[Name used to reference the value pushed into the Value Stack]]></description> <name>var</name> <required>false</required> <rtexprvalue>false</rtexprvalue> </attribute> <dynamic-attributes>false</dynamic-attributes> </tag>
protected void populateParams() { super.populateParams(); Date d = (Date) component; d.setName(name); d.setFormat(format); d.setNice(nice); Float timeZoneFloat = (Float) ActionContext.getContext().getSession().get("timeZone"); if (timeZoneFloat == null) { timezone = "GMT+08:00"; } else { timezone = formatFloatToTimeZone(timeZoneFloat); } d.setTimezone(timezone); }
上传,写个convert:
java.util.Calendar=my.utils.DateConverter
加到xwork-conversion.properties里面DateConverter里面重要的方法。
public Object convertFromString(Map context, String[] values, Class toClass) { Calendar cal = Calendar.getInstance(); Date date = null; String dateString = values[0]; DateFormat format = null; for (int i = 0; i < ACCEPT_DATE_FORMATS.length; i++) { format = ACCEPT_DATE_FORMATS[i]; try { if (i == 4) { date = new Date(); cal.setTime(date); cal.set(Calendar.HOUR_OF_DAY, Integer.parseInt(dateString.substring(0, 2))); cal.set(Calendar.MINUTE, Integer.parseInt(dateString.substring(3, dateString.length()))); Utils.changeTimeZoneForIn(cal); } else { date = format.parse(dateString); cal.setTime(date); Utils.changeTimeZoneForIn(cal); } return cal; } catch (Exception e) { continue; } } return null; }
5。 最一差点忘记了,web.xml里面一定要配置filter和tag,就不贴了看源代码吧
我想说的struts2 让人配起来好累。下次找个时间把它做了。自己写个
文章长了写的人累,看的人更累,别外两个配置放到其他一个BLOG里吧。