以下是本人在學習過程中做的一點點小小的總結,在這里留個副本!
現有代碼存在的問題:
為了解決每個業務模塊對應一個Servlet,Servlet過多的問題
解決辦法:
使用一個新的Servlet,匯總了所有的業務模塊Servlet,增加邏輯判斷,具體調用哪個業務Servlet
public class ServletAction extends HttpServlet {
//未抽取之前;
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String path = request.getServletPath();
if(path.indexOf("/userServlet.action") >=0 ){
//userService.getList(name);
request.setAttribute("user", "user");
this.getServletContext().getRequestDispatcher("/user/user_list.jsp").forward(request, response);
}
if(path.indexOf("/roleServlet.action") >= 0) {
//roleService.getList();
request.setAttribute("role", "role");
this.getServletContext().getRequestDispatcher("/user/role_list.jsp").forward(request, response);
}
}
}
該匯總的Servlet在web.xml中注冊時,匹配多個,所有的Servlet路徑;
<servlet>
<servlet-name>ActionServlet</servlet-name>
<servlet-class>com.bjsxt.struts.ActionServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ActionServlet</servlet-name>
<url-pattern>/role/roleServlet.action</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>ActionServlet</servlet-name>
<url-pattern>/user/userServlet.action</url-pattern>
</servlet-mapping>
抽取匯總的ServletAction:
各業務Servlet中重復的一些業務代碼抽取出來,成為一個單獨的類UserAction, RoleAction
同時,forward的頁面轉向的Url也可以從這些單獨的類中返回;
這些單獨的類擁有同一個方法execute(),返回值為在forward的頁面轉向的Url,該方法中執行各自的業務邏輯,由此,抽象出他們共同的接口Iaction;
public interface IAction {
public String execute(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException ;
}
public class UserAction implements IAction{
public String execute(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
//roleService.getList(name);
request.setAttribute("role", "role");
return "/user/user_list.jsp";
}
}
public class RoleAction implements IAction {
public String execute(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
//userService.getList(name);
request.setAttribute("user", "user");
return "/user/role_list.jsp";
}
}
在匯總的ServletAction中只需要有一個IAction的引用,指向不同的子類對象;
public class ServletAction extends HttpServlet {
// 抽取以后;
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String path = request.getServletPath();
if(path.indexOf("/userServlet.action") >=0 ){
IAction action = new UserAction();
String url = action.execute(request, response);
this.getServletContext().getRequestDispatcher(url).forward(request, response);
}
if(path.indexOf("/roleServlet.action") >= 0) {
IAction action = new UserAction();
String url = action.execute(request, response);
this.getServletContext().getRequestDispatcher(url).forward(request, response);
}
}
}
由于每增加一個業務邏輯Action,都需要在匯總的ServletAction中進行判斷,代碼冗余繁瑣,所以需要動態調用每個Action;
實現動態調用的思路:
得到一個map,key里面存放所有的ServletPath,value存放對應的類及jsp;
(以前我們實現動態調用使用反射機制)
分析現狀:得到每個ServletPath,根據每個ServletPath映射到不同的Action,從而取得要轉向的頁面;
解決辦法:寫一個struts-config.xml配置文件,定義每個ServletPath(web.xml中的url-patten),及對應的Servlet類(需要調用的Action類即子類對象),及對應的轉向頁面;
<?xml version="1.0" encoding="UTF-8"?>
<action-mappings>
<action path="/user/userServlet.action" type="com.bjsxt.struts.UserAction" forward="/user/user_list.jsp" />
<action path="/role/roleServlet.action" type="com.bjsxt.struts.RoleAction" forward="/user/role_list.jsp" />
</action-mappings>
如何解析這個xml文件呢?
使用jdom API,新建一個類XMLReader,其中定義read()方法;
引入jdom .jar文件
public class XMLReader {
//將xml文件中的一個標簽元素及其屬性存儲到一個Map中;
public static void read() {
SAXBuilder builder = new SAXBuilder();
Document doc = null;
Map map = new HashMap();
try {
doc = builder.build(Thread.currentThread().getContextClassLoader()
.getResourceAsStream("struts-config.xml"));
Element e = doc.getRootElement();
System.out.println(e);
List list = e.getChildren();
for(Iterator i= list.iterator(); i.hasNext();) {
ActionMapping am = new ActionMapping();
Element element = (Element)i.next();
am.setPath(element.getAttributeValue("path"));
am.setType(element.getAttributeValue("type"));
am.setForward(element.getAttributeValue("forward"));
//把一個ActionMapping放進Map中;使用put()方法;
map.put(element.getAttributeValue("path"), am);
}
} catch (JDOMException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
} 將解析得到的document,element的值放入一個map中;
為了使這個類只被ActionServlet調用一次,載入內存,其他任何類不得調用,重構這個XMLReader類的代碼:
map設置為靜態成員變量;
如果不采用在tomcat啟動的時候把XMLReader載入內存的方式的話,使用什么方法呢?
因為XMLReader運行在JVM和Tomcat下的調用機制是不同的,JVM是不需要用到該類就載入內存,而tomcat是用到該類才載入內存;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
public class XMLReader {
private static Map map = new HashMap();
private static final XMLReader xr = new XMLReader();
private XMLReader(){
read();
}
public static XMLReader getInstance() {
return xr;
}
//將xml文件中的一個標簽元素及其屬性存儲到一個Map中;
private void read() {
SAXBuilder builder = new SAXBuilder();
Document doc = null;
try {
doc = builder.build(Thread.currentThread().getContextClassLoader()
.getResourceAsStream("struts-config.xml"));
Element e = doc.getRootElement();
System.out.println(e);
List list = e.getChildren();
for(Iterator i= list.iterator(); i.hasNext();) {
ActionMapping am = new ActionMapping();
Element element = (Element)i.next();
am.setPath(element.getAttributeValue("path"));
am.setType(element.getAttributeValue("type"));
am.setForward(element.getAttributeValue("forward"));
//把一個ActionMapping放進Map中;使用put()方法;
map.put(element.getAttributeValue("path"), am);
}
} catch (JDOMException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
//定義一個根據key得到map中的值的方法;
public static ActionMapping getActionMapping(String path) {
return (ActionMapping)map.get(path);
}
public static void main(String[] args) {
getInstance().read();
}
ActionServlet調用XMLReader的代碼重構;
// 調用XMLReader;
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String path = request.getServletPath();
ActionMapping am = XMLReader.getActionMapping(path);
String forward = am.getForward() ;
String type = am.getType();
IAction action = null;
try {
action = (IAction)Class.forName(type).newInstance();
action.execute(request, response);
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.getServletContext().getRequestDispatcher(forward).forward(request, response);
}
以后如果增加新的業務,只需要增加Action類,配置文件中配置好就可以了
現在存在的問題:
直接Forward出去;用戶想更靈活,在Action中定義轉向的頁面;
業務中不同的條件forward到不同的頁面怎么辦;
辦法:改造配置文件中的forward屬性
<?xml version="1.0" encoding="UTF-8"?>
<action-mappings>
<action path="/user/userServlet.action" type="com.bjsxt.struts.UserAction" >
<forward name="sucsess" path="/user/user_list.jsp"></forward>
<forward name="failure" path="/user/user_list.jsp"></forward>
</action>
<action path="/role/roleServlet.action" type="com.bjsxt.struts.RoleAction" >
<forward name="sucsess" path="/user/role_list.jsp"></forward>
<forward name="failure" path="/user/role_list.jsp"></forward>
</action>
</action-mappings>
修改ActionMapping:
package com.bjsxt.struts;
import java.util.Map;
public class ActionMapping {
private String path;
private String type;
private Map map;
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Map getMap() {
return map;
}
public void setMap(Map map) {
this.map = map;
}
}
修改讀取XML的類XMLReader:
//將xml文件中的一個標簽元素及其屬性存儲到一個Map中;
private void read() {
SAXBuilder builder = new SAXBuilder();
Document doc = null;
try {
doc = builder.build(Thread.currentThread().getContextClassLoader()
.getResourceAsStream("struts-config.xml"));
Element e = doc.getRootElement();
System.out.println(e);
List list = e.getChildren();
for(Iterator i= list.iterator(); i.hasNext();) {
ActionMapping am = new ActionMapping();
Element element = (Element)i.next();
am.setPath(element.getAttributeValue("path"));
am.setType(element.getAttributeValue("type"));
//am.setForward(element.getAttributeValue("forward"));
List forward = element.getChildren();
Map m = new HashMap();
for(Iterator t= forward.iterator(); t.hasNext();) {
Element forwardemle = (Element)t.next();
m.put(forwardemle.getAttributeValue("name"), forwardemle.getAttributeValue("path"));
}
//把一個ActionMapping放進Map中;使用put()方法;
am.setMap(m);
map.put(element.getAttributeValue("path"), am);
}
} catch (JDOMException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
修改ServletAction,以前是通過Map中的ActionMapping的getPath()轉向,改為通過UserAction返回的Path進行forward轉向;
// 調用XMLReader;
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String path = request.getServletPath();
ActionMapping am = XMLReader.getActionMapping(path);
//String forward = am.getForward() ;
String type = am.getType();
IAction action = null;
String url = null;
try {
action = (IAction)Class.forName(type).newInstance();
url = action.execute(request, response);
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.getServletContext().getRequestDispatcher(url).forward(request, response);
}
修改UserAction,增加判斷轉向邏輯;
public String execute(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
//roleService.getList(name);
request.setAttribute("role", "role");
String path = request.getServletPath();
//需要得到ActionMapping;
ActionMapping am = XMLReader.getActionMapping(path);
//forward的兩個屬性放到map中了;
Map m = am.getMap();
/*
if(true) {
return(String) m.get("failure");
}*/
return (String)m.get("sucess");
}
存在的問題:
每一個Action,如UserAction都要得到ActionMapping,麻煩;
辦法:
ActionServlet中存在ActionMapping,把它當作參數傳到UserAction中;
public String execute(HttpServletRequest request,
HttpServletResponse response, ActionMapping am) throws ServletException, IOException {
//roleService.getList(name);
request.setAttribute("role", "role");
String path = request.getServletPath();
/*if(true) {
return(String) m.get("failure");
}*/
//return (String)am.getMap().get("sucess");
//改造ActionMapping類,增加getPath(String path)方法,得到Map中的getPath();
/*public String getPath(String path) {
return (String)map.get(path);
}*/
return am.getPath(path);
存在的問題:
sendRedirect不好用了
辦法:
重新設置配置文件;
<?xml version="1.0" encoding="UTF-8"?>
<action-mappings>
<action path="/user/userServlet.action" type="com.bjsxt.struts.UserAction" >
<forward name="sucsess" path="/user/user_list.jsp" redirect="false"></forward>
<forward name="failure" path="/user/user_list.jsp" redirect="false"></forward>
</action>
<action path="/role/roleServlet.action" type="com.bjsxt.struts.RoleAction" >
<forward name="sucsess" path="/user/role_list.jsp" redirect="true"></forward>
<forward name="failure" path="/user/role_list.jsp" redirect="true"></forward>
</action>
</action-mappings>
由于Forward有三個屬性,直接放在Map中不合適了,所以增加ActionForward類:
package com.bjsxt.struts;
public class ActionForward {
private String name;
private String path;
private boolean redirect;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public boolean isRedirect() {
return redirect;
}
public void setRedirect(boolean redirect) {
this.redirect = redirect;
}
}
修改XMLReader:
private void read() {
SAXBuilder builder = new SAXBuilder();
Document doc = null;
try {
doc = builder.build(Thread.currentThread().getContextClassLoader()
.getResourceAsStream("struts-config.xml"));
Element e = doc.getRootElement();
System.out.println(e);
List list = e.getChildren();
for(Iterator i= list.iterator(); i.hasNext();) {
ActionMapping am = new ActionMapping();
Element element = (Element)i.next();
am.setPath(element.getAttributeValue("path"));
am.setType(element.getAttributeValue("type"));
//am.setForward(element.getAttributeValue("forward"));
List forward = element.getChildren();
Map m = new HashMap();
for(Iterator t= forward.iterator(); t.hasNext();) {
Element forwardemle = (Element)t.next();
ActionForward actionForward = new ActionForward();
actionForward.setName(forwardemle.getAttributeValue("name"));
actionForward.setPath(forwardemle.getAttributeValue("path"));
actionForward.setRedirect(Boolean.valueOf(forwardemle.getAttributeValue("redirect")));
m.put(forwardemle.getAttributeValue("name"),actionForward);
}
//把一個ActionMapping放進Map中;使用put()方法;
am.setMap(m);
map.put(element.getAttributeValue("path"), am);
}
} catch (JDOMException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
修改UserAction增加返回值;
UserAction應該不只是返回URL,還應該返回isRedirect,所以,它應該返回一個ActionForward對象:
public ActionForward execute(HttpServletRequest request,
HttpServletResponse response, ActionMapping am) throws ServletException, IOException {
//roleService.getList(name);
request.setAttribute("role", "role");
//String path = request.getServletPath();
//改造ActionMapping類,增加getPath(String path)方法,得到Map中的getPath();
/*public ActionMapping getPath(String path) {
return (String)map.get(path);
}*/
return am.getPath("success");
}
根據傳過來的ActionForward對象,ServletAction判斷是forward還是sendRedirect?
protected void service(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
String path = request.getServletPath();
ActionMapping am = XMLReader.getActionMapping(path);
// String forward = am.getForward() ;
String type = am.getType();
IAction action = null;
ActionForward actionForward = null;
try {
action = (IAction) Class.forName(type).newInstance();
actionForward = action.execute(request, response);
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (actionForward.isRedirect()) {
response.sendRedirect(request.getContextPath()
+ actionForward.getPath());
} else {
this.getServletContext().getRequestDispatcher(
actionForward.getPath()).forward(request, response);
}
}
存在的問題:明天解決
解決request對象依賴過多的問題:
如何讓它自動映射,不需要從request.getParameter()拿數據.