以下是本人在学习过程中做的一点点小小的总结,在这里留个副本!


现有代码存在的问题:

为了解决每个业务模块对应一个ServletServlet过多的问题

解决办法:

使用一个新的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);

}

}

}

该汇总的Servletweb.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运行在JVMTomcat下的调用机制是不同的,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中的ActionMappinggetPath()转向,改为通过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()拿数据.