一、 防止查看源码,直接访问JSP
两种方法:
1. 不要让用户直接访问任何JSP页面,起始页可以是HTML文档。在web.xml中增加下面的行来阻止用户直接访问JSP页面。
<
web-app
>
...
< security-constraint >
< web-resource-collection >
< web-resource-name > no_access </ web-resource-name >
< url-pattern > *.jsp </ url-pattern >
</ web-resource-collection >
< auth-constraint />
</ security-constraint >
...
</ web-app >
...
< security-constraint >
< web-resource-collection >
< web-resource-name > no_access </ web-resource-name >
< url-pattern > *.jsp </ url-pattern >
</ web-resource-collection >
< auth-constraint />
</ security-constraint >
...
</ web-app >
2. 最常见的选择是把JSP页面藏在WEB-INF文件夹的后面。这只能算一种折衷方案。例如,你不能把javascript/css文件隐藏在WEB-INF后面,并且如果你使用Struts组件,可能还会遇到一些上下文相关的问题。
建议:第二种方法允许一些JSP页面(那些不能被放在WEB-INF后面的)直接可见。不要求描述文件,因而,最佳实践是把页面放在WEB-INF后面。
二、每写个应用都用继承BaseAction ,和BaseForm , 当然BaseAction 最好是继承LookupDispatchAction, BaseForm 最好是继承ValidatorActionForm。建议一个用例一个Action,多个用例多个Action,一个用例中的CURD操作在一个Action内。
三、异常处理(1)
Struts Action中处理的异常,已经不该是你的原始异常了.在你的Dao层要抛出DataException,而在你的业务层,需要捕获到,作为你的自定义异常抛出,这样你在struts里捕获到的异常才是友好的,且是有意义的.
我们都知道Dao那一层都是抛一个统一的异常比如DataExpcetion,然后到你的业务处Service 那一层能就捕获DataExpcetion, 因为Serivce那一层,你总归是知道自己要做什么, 因此建议在Service 那层捕获DataException 之后,打印debug日志,然后再抛出业务逻辑异常
比如在业务处理,添加一个学生过程,如果Service层中:
public
void
doAddStudent(Student student)
throws
DupKeyExption,Ser{
try {
if ((Student)load(student.getId()).getId() == student.getId()){
throw new DupKeyExcption( " 改同学已经存在 " );
}
studentDao.add();
} catch (DataException e){
logger.debug( " 错误信息: " ,e);
throws new StudentException( " 增加失败 " );
}
}
try {
if ((Student)load(student.getId()).getId() == student.getId()){
throw new DupKeyExcption( " 改同学已经存在 " );
}
studentDao.add();
} catch (DataException e){
logger.debug( " 错误信息: " ,e);
throws new StudentException( " 增加失败 " );
}
}
try
{
service.doAddStudent();
} catch (DupikeyException e1){
// 重复添加了
errors.add( " message " , new ActionError( " student.error.dupkey " ));
} catch (Exception e) {
// 添加失败
errors.add( " message " , new ActionError( " student.error.add " ));
logger.error(e.getMessage());
e.printStackTrace();
}
saveErrors(request, errors);
service.doAddStudent();
} catch (DupikeyException e1){
// 重复添加了
errors.add( " message " , new ActionError( " student.error.dupkey " ));
} catch (Exception e) {
// 添加失败
errors.add( " message " , new ActionError( " student.error.add " ));
logger.error(e.getMessage());
e.printStackTrace();
}
saveErrors(request, errors);
<
html:messages
id
="message"
>
< script language =javascript > window.alert( ' <bean:write name="message"/> ' ) </ script >
</ html:messages >
< script language =javascript > window.alert( ' <bean:write name="message"/> ' ) </ script >
</ html:messages >
四、异常处理(2)
作为通用的原则,错误应该被在他们发生的地方正确的捕捉显示有意义的错误信息。要实现这个原则,程序员必须写他们自己的定制异常类。封装实际的异常到他们的定制异常类,把他们抛出到要处理的地方。在基于Struts的应用中,异常在Web/EJB层抛出,在Action类中或者form bean中处理。通常的实践是在Action类或form bean中写try-catch代码捕捉异常,使用从应用属性文件中派生的用户友好的错误信息创建一个ActionError对象,使用ActionMapping.findForward()方法。
你必须在Action类中编写所有的这些异常处理代码。如果错误处理策略改变了,每个Action或者form bean都要改变。
Struts最佳实践
Struts用适当的方法解决异常处理问题,使用声明型的异常处理。与编码型的异常处理相反,异常处理使用RequestProcessor类的processException()方法和一个Struts配置文件。要使用声明型的异常处理,你必须按照下面的步骤:
1. 创建定制应用异常类。可以设计他们,以便处理超过一种异常。
2. 在WEB/EJB层,捕获应用错误并且封装错误到定制异常中,把异常抛出。
3. 在struts-config.xml文件中,增加如下内容:
<
struts-config
>
< action-mappings >
< action
path ="yourAction"
type ="your.package.yourAction"
input ="input.jsp" >
< exception
key ="your.error.property.key"
path ="yourException.jsp"
type ="your.application.custom.exception"
</action >
</ action-mappings >
< action-mappings >
< action
path ="yourAction"
type ="your.package.yourAction"
input ="input.jsp" >
< exception
key ="your.error.property.key"
path ="yourException.jsp"
type ="your.application.custom.exception"
</action >
</ action-mappings >
五、错误分类
在N层应用中错误处理变得复杂。在基于浏览器的应用中,错误处理可以在客户端使用JavaScript以及在使用专用java方法的WEB层或EJB层。Struts提供了ActionMessages/ActionErrors类来维护需要被报告的错误信息堆栈,能使用<html:error>之类的tag显示给用户的错误信息。问题是用不同的风格,例如error,warning或者information,报告不同类型的错误。
1.在合适的类别下注册错误
2.识别这些信息,并且始终如一的显示他们。
Struts最佳实践
Struts的ActionError类方便的解决了不同类型堆栈信息的第一个问题。要显示不同类型的错误信息,在一个接口内定义这些类型,FATAL,ERROR,WARNING,INFO。然后在Action或form bean中,你可以这样使用:
errors.add(
"
fatal
"
,
new
ActionError(
"
....
"
)); 或
errors.add( " error " , new ActionError( " .... " )); 或
errors.add( " warning " , new ActionError( " .... " )); 或
errors.add( " information " , new ActionError( " .... " ));
saveErrors(request,errors);
errors.add( " error " , new ActionError( " .... " )); 或
errors.add( " warning " , new ActionError( " .... " )); 或
errors.add( " information " , new ActionError( " .... " ));
saveErrors(request,errors);
<
logic:messagePresent
property
="error"
>
< html:messages property ="error" id ="errMsg" >
< bean:write name ="errMsg" />
</ html:messages >
</ logic:messagePresent >
< html:messages property ="error" id ="errMsg" >
< bean:write name ="errMsg" />
</ html:messages >
</ logic:messagePresent >
<
logic:messagePresent
property
="error"
>
< html:messages property ="error" id ="errMsg" >
showError(' < bean:write name ="errMsg" /> '); // JavaScript Function
</ html:messages >
</ logic:messagePresent >
< html:messages property ="error" id ="errMsg" >
showError(' < bean:write name ="errMsg" /> '); // JavaScript Function
</ html:messages >
</ logic:messagePresent >
六、关于DTO、VO及PO的处理,建议用VO代替DTO,从V层到C层时,用BeanUtils中的copyProperties()方法将VO构造成POJO再传入M层,从数据库中取出时,也用BeanUtils让PO转为VO再显示(取出与写入时注意数据类型,尤其是从V层写入M层时),另外BO的生存范围请控制最大只能到C层。
七、堆栈维护
开发人员经常需要以交叉的方式访问不同的页面,应用必须要记住访问过的页。
补偿是在Stack(java.util.Stack)中保存所有转向过的JSP页面的路径。
1.继承RequestProcessor类,覆写processActionPerform()方法。在覆写的方法中,调用super.processActionPerform()方法后,ActionForward的路径应该被保存在Stack中。
2.在应用的父Action类中,提供方法在堆栈中向前或向后访问。
另一种选择是利用已经存在的开源项目,例如sf.net的Open Tranquera。