MVC之前的开发形式:
jsp à通过web.xml找到要提交的Servlet à进入doGet或doPost,依据status判断不同的操作,接收参数,验证整合,调用DAO,接收结果并设置,跳转(通过request.getRequestDispatch().forward())à JSP
Struts的开发形式:
jsp à通过web.xml找到ActionServlet(由Struts提供,不需要自己建立)à找到Struts中核心的两个操作类ActionForm,Action à先进入ActionForm,接收参数,并验证à如果验证不通过,直接返回jsp,并提示错误信息à如果通过,则进入Action,完成其他操作,跳转时,不需要自己再使用request的跳转方法,只需要传入跳转的页面名称就可以自动跳转回jsp。
1、Struts完成登陆
假设输入的用户名为MLDN密码为123表示登陆成功。
建立项目,为项目加入Struts支持。
这里的struts-config.xml是Struts框架的核心配置文件。
加入支持后,项目中多出以下内容:
1) 支持类库
2) WEB-INF下多出一个struts-config.xml
3) src下多出一个.properties属性文件
4) web.xml中多出了ActionServlet的配置
<servlet> <servlet-name>action</servlet-name> <servlet-class>org.apache.struts.action.ActionServlet</servlet-class> <init-param> <param-name>config</param-name> <param-value>/WEB-INF/struts-config.xml</param-value> </init-param> <init-param> <param-name>debug</param-name> <param-value>3</param-value> </init-param> <init-param> <param-name>detail</param-name> <param-value>3</param-value> </init-param> <load-on-startup>0</load-on-startup> </servlet> <servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> |
可以修改里面的config配置,加入多个struts-config.xml配置文件。
先完成登陆页
<html:form action="login.do" method="post"> 用户ID:<html:text property="userid"></html:text> <br /> 密码:<html:password property="password"></html:password> <br /> <html:submit value="登陆"></html:submit> <html:reset>重置</html:reset> </html:form> |
表单建议使用Struts提供的html标签。
不再通过name来定义名称,而改为使用property。
建立ActionForm与Action,替代之前Servlet的操作
选择建立ActionForm与Action
注意修改InputSource,路径改为出错后跳转的路径,这里变成index.jsp
先编写ActionForm,在ActionForm中需要先接收参数。
参数只需要定义同名的属性,并生成getter和setter方法就可以接收。
参数接收后,会自动进入validate方法完成验证操作。
package cn.mldn.struts.form;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts.action.ActionErrors; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionMapping; import org.apache.struts.action.ActionMessage;
publicclass LoginForm extends ActionForm {
private String userid; private String password;
public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) { ActionErrors errors = new ActionErrors(); // 比如在这里验证用户名或密码不能为空 if (userid == null || userid.trim().equals("")) { // 加入错误信息 // 在Struts中错误信息为了方便统一管理和重复使用,都会配置到properties属性文件中 errors.add("userid", new ActionMessage("userid.null")); } if (password == null || password.trim().equals("")) { errors.add("password", new ActionMessage("password.null")); } return errors; }
publicvoid reset(ActionMapping mapping, HttpServletRequest request) { }
public String getUserid() { returnuserid; }
publicvoid setUserid(String userid) { this.userid = userid; }
public String getPassword() { returnpassword; }
publicvoid setPassword(String password) { this.password = password; } }
错误信息的properties文件 userid.null=\u7528\u6237\u540D\u4E0D\u80FD\u4E3A\u7A7A\uFF01 login.err=\u7528\u6237\u540D\u6216\u5BC6\u7801\u9519\u8BEF\uFF0C\u8BF7\u91CD\u65B0\u8F93\u5165\uFF01 password.null=\u5BC6\u7801\u4E0D\u80FD\u4E3A\u7A7A\uFF01 |
这里使用到了ActionErrors(保存所有错误信息的一个集合),ActionMessage(用来根据名称查找具体的错误信息)
Struts会自动依据ActionErrors中是否包含错误信息来决定进入错误页还是Action。
如果返回错误页,需要通过<html:errors/>标签显示错误信息。
<center> <font color="red"><html:errors/></font> <html:form action="login.do" method="post"> 用户ID:<html:text property="userid"></html:text> <br /> 密码:<html:password property="password"></html:password> <br /> <html:submit value="登陆"></html:submit> <html:reset>重置</html:reset> </html:form>
</center> |
在Action中,验证用户名或密码是否正确
package cn.mldn.struts.action;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action; import org.apache.struts.action.ActionErrors; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import org.apache.struts.action.ActionMessage;
import cn.mldn.struts.form.LoginForm;
publicclass LoginAction extends Action { public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { LoginForm loginForm = (LoginForm) form; // 通过form取得参数,并执行验证 if (loginForm.getUserid().equals("MLDN") && loginForm.getPassword().equals("123")) { // 登陆成功 request.getSession().setAttribute("userid", loginForm.getUserid()); // 跳转到成功页 return mapping.findForward("suc"); } else { // 登陆失败 // 提取错误信息 ActionErrors errors = new ActionErrors(); errors.add("login", new ActionMessage("login.err")); // 保存错误 super.addErrors(request, errors); // 返回错误页 // mapping对象就是用来查找各种跳转页面路径的 return mapping.getInputForward(); } } } |
在Action中不写具体的跳转路径,只写名称,而路径要通过struts-config.xml来查找。
打开Struts-config.xml
<action attribute="loginForm" input="/index.jsp" name="loginForm(与前面的formbean的那么对应)" path="/login"(与页面的login.do对应) scope="request" type="cn.mldn.struts.action.LoginAction" cancellable="true"> <forward name="suc" path="/pages/suc.jsp"></forward> </action> |
通过<forward>来配置跳转路径。
整个Struts-config.xml配置文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN" "http://struts.apache.org/dtds/struts-config_1_3.dtd">
<struts-config> <form-beans>
<form-bean name="loginForm" type="cn.mldn.struts.form.LoginForm" />
</form-beans> <global-exceptions /> <global-forwards /> <action-mappings>
<action attribute="loginForm" input="/index.jsp" name="loginForm"
path="/login" scope="request" type="cn.mldn.struts.action.LoginAction" cancellable="true"> <forward name="suc" path="/pages/suc.jsp"></forward> </action>
</action-mappings> <message-resources parameter="cn.mldn.struts.ApplicationResources" /> </struts-config> |
2、Struts核心配置以及常用API
常用的API:
1) Action:编写自己的Action类时都要继承这个类,并覆写里面的execute方法
a) addErrors():设置错误信息,需要传入一个ActionErrors和一个request对象
2) ActionForm:编写自己的ActionForm类时要继承这个类,并覆写validate验证方法
a) validate():需要返回一个ActionErrors,Struts会自动根据这个对象中的错误信息决定是否跳转到错误页
3) ActionErrors:保存多条错误信息的集合
a) add():添加错误信息
b) size():取得里面错误信息的数量,用来判断是否出错
4) ActionMessage:查找一条错误信息,需要在构造方法中传入错误信息名称
5) ActionMapping:用来从struts-config.xml中查找跳转路径的
a) findForward():查找普通的跳转路径
b) getInputForward():查找错误页路径
struts-config.xml中的配置:
<form-beans>:里面包含了所有的ActionForm的配置。
<form-bean>:对应一个ActionForm
type:该对象的包.类名称
name:这个ActionForm的唯一标识,不能重复
<global-exceptions>:全局的异常配置信息,可以配置在出现异常时自动跳转的页面
<exception>:配置某一个异常
type:加入异常的包.类名称
path:自动跳转的路径
<global-forwards>:配置全局的跳转路径,这里配置的<forward>可以在所有的Action中使用
<action-mappings>:配置所有的<action>
<action>:对应一个Action对象
type:包.类名
input:错误页路径,必须以 / 开头
path:进入这个Action和对应的ActionForm的路径。不允许重复,因为如果重复在提交时会无法判断该进入哪个Action
name:表示这个Action和哪个ActionForm一起使用。可以多个Action共同使用一个ActionForm,所以这个name是可以重复的
scope:表示ActionForm保存的属性范围,可以选择request或session范围,一般都使用request
attribute:在属性范围中定义的名称。
<forward>:定义一个跳转路径,可以通过mapping.findForward()方法查找到。优先级比全局跳转路径要高。
name:路径的唯一标识
path:具体的跳转路径,必须以 / 开头
redirect:是否使用客户端跳转,默认值是false。
<message-resources>:配置属性文件所在位置和文件名。允许加入多个资源文件。
Struts工作原理:
jsp à提交后依据.do在web.xml中找到ActionServlet,读取struts-config.xml文件,找到对应的ActionForm与Action à建立ActionForm,进行参数接收,并调用validate方法进行验证
à验证失败,进入错误页(依据struts-config.xml中的input配置)
à验证成功,进入Action,执行execute()方法,最后跳转到jsp中(从struts-config.xml中查找<forward>路径进行跳转)
3、ActionForm中的参数接收
按照Servlet中通过request.getParameter接收参数返回类型应该是String。
而在ActionForm中接收可以自动转换基本数据类型的数据。
在这里如果输入合法的数据,则会自动转型,如果输入非法数据,会按照该类型的默认值进行处理。
<html:form action="regist.do" method="post"> 用户ID:<html:text property="userid"></html:text> <br /> 密码:<html:password property="password"></html:password> <br /> 年龄:<html:text property="age"></html:text><br/> <html:submit value="注册"></html:submit> <html:reset>重置</html:reset> </html:form> |
private Integer age;
|
基本数据类型中,如果要接收并自动转换boolean类型数据,要求页面提供的值必须在以下范围内:
true,false,1,0
可以在一些判断的多选框中使用,例如:
<html:form action="regist.do" method="post"> 用户ID:<html:text property="userid"></html:text> <br /> 密码:<html:password property="password"></html:password> <br /> 年龄:<html:text property="age"></html:text><br/> 是否接收系统邮件:<html:checkbox property="flag" value="true"></html:checkbox> <br/> <html:submit value="注册"></html:submit> <html:reset>重置</html:reset> </html:form> |
对于日期类型,如果使用Servlet开发,需要先用String接收,再通过SimpleDateFormat转换为java.util.Date类型。
而在Struts1中也需要这样处理。
private String birthday;
public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) { SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd"); try { System.out.println(sf.parse(birthday)); } catch (ParseException e) { // TODO Auto-generated catch block e.printStackTrace(); }
returnnull; } |
ActionForm还允许直接向对象中的属性设置参数值。
<font color="red"><html:errors/></font> <html:form action="regist.do" method="post"> 用户ID:<html:text property="user.userid"></html:text> <br /> 密码:<html:password property="user.password"></html:password> <br /> 年龄:<html:text property="user.age"></html:text><br/> 生日:<html:text property="birthday"></html:text><br/> <html:submit value="注册"></html:submit> <html:reset>重置</html:reset> </html:form> //id和密码都是作为属性存放在对象里接收,那么后台就只要new一个user对象就可以直接拿到这两个属性,而生日则需要后台处理后单独往里面set |
接下来:
package cn.mldn.struts.form;
import java.text.ParseException; import java.text.SimpleDateFormat;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts.action.ActionErrors; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionMapping; import org.apache.struts.action.ActionMessage;
import cn.mldn.vo.User;
publicclass RegistForm extends ActionForm {
private User user= new User();
private String birthday;
public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) { ActionErrors errors = new ActionErrors();
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd"); try { user.setBirthday(sf.parse(birthday)); //因为页面上没有把user的birthday作为属性封装,所以需要单独的来转换后接收
} catch (ParseException e) { errors.add("birthday", new ActionMessage("date.format.err")); }
return errors; }
publicvoid reset(ActionMapping mapping, HttpServletRequest request) { }
publicvoid setBirthday(String birthday) { this.birthday = birthday; }
public String getBirthday() { returnbirthday; }
public User getUser() { returnuser; }
publicvoid setUser(User user) { this.user = user; }
} |
处理参数时,注意:
1) 如果要直接设置到vo对象的属性中,需要先将vo对象实例化
2) 日期类型不要直接设置到Date数据类型中,需要先使用String接收,再通过SimpleDateFormat转换后设置到vo中,转换的同时可以加入错误信息的提示。
4、分发
可以用来完成分发操作。
JSP页面是
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP 'index.jsp' starting page</title> </head>
<body> <center> <a href="${pageContext.request.contextPath}/pages/news_insert.jsp">添加新闻</a> <br /> <a href="${pageContext.request.contextPath}/news.do?status=list">新闻列表</a> <br /> <a href="${pageContext.request.contextPath}/news.do?status=selectlist">下拉列表显示</a> <br />
</center> </body> </html> |
actionForm
package cn.mldn.news.struts.form;
import java.text.ParseException; import java.text.SimpleDateFormat;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts.action.ActionErrors; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionMapping; import org.apache.struts.action.ActionMessage;
import cn.mldn.news.vo.News;
public class NewsForm extends ActionForm { private News news = new News(); private String postDate; private String status;
private int cp = 1; private int ls = 5; private String kw = ""; private String lan; private int areaid = 4; private Integer[] sports = {2,3};
public Integer[] getSports() { return sports; }
public void setSports(Integer[] sports) { this.sports = sports; }
public int getAreaid() { return areaid; }
public void setAreaid(int areaid) { this.areaid = areaid; }
public int getCp() { return cp; }
public void setCp(int cp) { this.cp = cp; }
public int getLs() { return ls; }
public void setLs(int ls) { this.ls = ls; }
public String getKw() { return kw; }
public void setKw(String kw) { this.kw = kw; }
public News getNews() { return news; }
public void setNews(News news) { this.news = news; }
public String getPostDate() { return postDate; }
public void setPostDate(String postDate) { this.postDate = postDate; }
public String getStatus() { return status; }
public void setStatus(String status) { this.status = status; }
public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) { ActionErrors errors = new ActionErrors();
if ("insert".equals(status) || "update".equals(status)) { if (news.getTitle() == null || news.getTitle().trim().equals("")) { errors.add("newstitle", new ActionMessage("news.title.null")); } SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); try { news.setPostDate(sf.parse(postDate)); } catch (Exception e) { errors.add("newspostDate", new ActionMessage( "news.postDate.err")); } }
return errors; }
public void reset(ActionMapping mapping, HttpServletRequest request) { }
public String getLan() { return lan; }
public void setLan(String lan) { this.lan = lan; } } |
在编写Action时,可以选择继承DispatchAction。
并将每个操作单独定义一个方法。
package cn.mldn.news.struts.action;
import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Map;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
import org.apache.struts.Globals; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import org.apache.struts.actions.DispatchAction;
import cn.mldn.news.factory.ServiceFactory; import cn.mldn.news.struts.form.NewsForm; import cn.mldn.news.vo.Area; import cn.mldn.news.vo.News;
publicclass NewsAction extends DispatchAction {
public ActionForward insert(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { NewsForm newsForm = (NewsForm) form; boolean flag = ServiceFactory.getNewsServiceInstance().doCreate( newsForm.getNews()); request.setAttribute("message", flag ? "添加成功" : "添加失败"); request.setAttribute("url", "/news.do?status=list");
return mapping.findForward("forward"); }
public ActionForward list(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { NewsForm newsForm = (NewsForm) form; Map map = ServiceFactory.getNewsServiceInstance().findAll( newsForm.getCp(), newsForm.getLs(), newsForm.getKw()); request.setAttribute("all", map.get("all")); request.setAttribute("count", map.get("count")); // cp ,ls,kw不需要再设置到request范围中,因此本身newsForm就在request范围里 request.setAttribute("url", "/news.do?status=list");
return mapping.findForward("list"); }
public ActionForward changeLan(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { NewsForm newsForm = (NewsForm) form; String[] str = newsForm.getLan().split("_"); Locale loc = new Locale(str[0], str[1]); // 将这个loc保存到Session属性范围中 request.getSession().setAttribute(Globals.LOCALE_KEY, loc);
return mapping.findForward("insert"); }
public ActionForward selectlist(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { NewsForm newsForm = (NewsForm) form; List all = new ArrayList(); Area a = new Area(); a.setId(1); a.setTitle("北京"); all.add(a); a = new Area(); a.setId(2); a.setTitle("上海"); all.add(a); a = new Area(); a.setId(3); a.setTitle("广东"); all.add(a); a = new Area(); a.setId(4); a.setTitle("天津"); all.add(a);
request.setAttribute("all", all); return mapping.findForward("selectlist"); }
public ActionForward updatepre(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { NewsForm newsForm = (NewsForm) form; // 查询出需要的vo对象 News news = ServiceFactory.getNewsServiceInstance().findById( newsForm.getNews().getId());
// 将vo对象设置到ActionForm中。页面上的html标签会自动取得内容,并设置默认值 newsForm.setNews(news); // 还需要将postDate值也设置上,为了让页面上的 postDate值可以自动回填 SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); newsForm.setPostDate(sf.format(news.getPostDate()));
// 跳转到修改页 return mapping.findForward("update"); }
public ActionForward update(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { NewsForm newsForm = (NewsForm) form; boolean flag = ServiceFactory.getNewsServiceInstance().doUpdate( newsForm.getNews()); request.setAttribute("message", flag?"修改成功":"修改失败"); request.setAttribute("url", "/news.do?status=list"); return mapping.findForward("forward"); }
} |
还需要在struts-config.xml中加入一个配置,使Struts了解要根据哪个参数进行分发判断。
<action attribute="newsForm" input="/pages/error.jsp" name="newsForm" path="/news" scope="request" parameter="status" type="cn.mldn.news.struts.action.NewsAction" cancellable="true"> |
这里分发Action可以在建立Action时就建立出来,而不需要写完以后再修改。