以下是本人在学习过程中做的一点点小小的总结,在这里留个副本!
现有代码存在的问题:
为了解决每个业务模块对应一个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()拿数据.