面向对象之路

来源:互联网 发布:windows线程同步机制 编辑:程序博客网 时间:2024/05/30 02:52

仿struts读取配置文件,完成如下要求: 

0. 读取配置文件struts.xml
  1. 根据actionName找到相对应的class , 例如LoginAction,   通过反射实例化(创建对象)据parameters中的数据,调用对象的setter方法, 例如parameters中的数据                          是 ("name"="test" ,  "password"="1234") ,  那就应该调用 setName和setPassword方法
2. 通过反射调用对象的exectue 方法, 并获得返回值,例如"success"
3. 通过反射找到对象的所有getter方法(例如 getMessage),  通过反射来调用, 把值和属性形成一个HashMap , 例如 {"message":  "登录成功"} ,  放到View对象的            parameters
4. 根据struts.xml中的 <result> 配置,以及execute的返回值,  确定哪一个jsp,放到View对象的jsp字段中。

自己的思路不清晰,代码杂乱不堪,完全是想一点写一点。

现将刘老师TDD实现思路及面向对象大法整理如下:

   public class ConfigurationTest {
Configuration cfg=new Configuration("struts.xml");
@Test
public void testGetClassName() {
String clzName=cfg.getClassName("login");
Assert.assertEquals("domain.LoginAction", clzName);

clzName = cfg.getClassName("logout");
Assert.assertEquals("domain.LogoutAction", clzName);
}
    @Test
public void testResultView(){
String jsp=cfg.getResultView("login","success");
Assert.assertEquals("/jsp/homepage.jsp",jsp);
}
}

一个用来读取配置文件并将class转换成其静态内部类,然后通过静态内部类的属性对应上类名。

public class Configuration {


Map<String,ActionConfig> actions = new HashMap<>();

public Configuration(String fileName) {

String packageName = this.getClass().getPackage().getName();

packageName = packageName.replace('.', '/');

InputStream is = this.getClass().getResourceAsStream("/" + packageName + "/" + fileName);

parseXML(is);

try {
is.close();
} catch (IOException e) {
throw new ConfigurationException(e);
}
}

private void parseXML(InputStream is){

SAXBuilder builder = new SAXBuilder();
 
try {
 
Document doc = builder.build(is);

Element root = doc.getRootElement();

for(Element actionElement : root.getChildren("action")){

String actionName = actionElement.getAttributeValue("name");
String clzName = actionElement.getAttributeValue("class");

ActionConfig ac = new ActionConfig(actionName, clzName);

for(Element resultElement : actionElement.getChildren("result")){

String resultName = resultElement.getAttributeValue("name");
String viewName = resultElement.getText().trim();

ac.addViewResult(resultName, viewName);

}

this.actions.put(actionName, ac);
}


} catch (JDOMException e) {
throw new ConfigurationException(e);

} catch (IOException e) {
throw new ConfigurationException(e);

}
 
 
}


public String getClassName(String action) {
ActionConfig ac = this.actions.get(action);
if(ac == null){
return null;
}
return ac.getClassName();
}


public String getResultView(String action, String resultName) {
ActionConfig ac = this.actions.get(action);
if(ac == null){
return null;
}
return ac.getViewName(resultName);
}

private static class ActionConfig{

String name;
String clzName;
Map<String,String> viewResult = new HashMap<>();


public ActionConfig(String actionName, String clzName) {
this.name = actionName;
this.clzName = clzName;
}
public String getClassName(){
return clzName;
}
public void addViewResult(String name, String viewName){
viewResult.put(name, viewName);
}
public String getViewName(String resultName){
return viewResult.get(resultName);
}
}

}

TDD加对象的职责划分,用一个工具类来处理反射。

public class ReflectionUtilTest {


@Test
public void testGetSetterMethod() throws Exception{
String name="domain.LoginAction";
Class<?> clz=Class.forName(name);
List<Method>methods =ReflectionUtil.getSetterMethods(clz);

Assert.assertEquals(2, methods.size());

List<String> expectedNames=new ArrayList<>();
expectedNames.add("setName");
expectedNames.add("setPassword");

Set<String> acctualNames=new HashSet<>();
for(Method m:methods){
acctualNames.add(m.getName());
}
Assert.assertTrue(acctualNames.containsAll(expectedNames));
}
    @Test
    public void testSetParameters() throws Exception{
    String name="domain.LoginAction";
    Class<?>clz=Class.forName(name);
    Object o=clz.newInstance();
    Map<String,String>params=new HashMap<String,String>();
    params.put("name", "test");
    params.put("password", "1234");
   
    ReflectionUtil.setParameters(o,params);
   
    Field f=clz.getDeclaredField("name");
    f.setAccessible(true);
    Assert.assertEquals("test", f.get(o));
   
    f=clz.getDeclaredField("password");
    f.setAccessible(true);
    Assert.assertEquals("1234", f.get(o));
    }
    @Test
    public void testGetGetterMethod()throws Exception{
    String name="domain.LoginAction";
    Class<?>clz=Class.forName(name);
    List<Method>methods=ReflectionUtil.getGetterMethods(clz);
   
    Assert.assertEquals(3, methods.size());
    List<String>expectedNames=new ArrayList<>();
    expectedNames.add("getMessage");
    expectedNames.add("getName");
    expectedNames.add("getPassword");
    Set<String> acctualNames=new HashSet<>();
for(Method m:methods){
acctualNames.add(m.getName());
}
Assert.assertTrue(acctualNames.containsAll(expectedNames));
    }
    @Test
    public void testGetParamters() throws Exception{
    String name="domain.LoginAction";
    Class<?> clz=Class.forName(name);
    LoginAction action=(LoginAction) clz.newInstance();
    action.setName("test");
    action.setPassword("123456");
   
    Map<String,Object> params=ReflectionUtil.getParamterMap(action);
    Assert.assertEquals(3, params.size());
   
    Assert.assertEquals(null, params.get("message"));
    Assert.assertEquals("test", params.get("name"));
    Assert.assertEquals("123456", params.get("password"));
    }
}

工具类用来封装对象的get、set方法,来对对象的属性值的射入和获取。

public class ReflectionUtil {
public static List<Method> getSetterMethods(Class<?> clz) {
return getMethods(clz, "set");
}


private static List<Method> getMethods(Class<?> clz, String startWithName) {
List<Method> methods = new ArrayList<>();
for (Method m : clz.getDeclaredMethods()) {
if (m.getName().startsWith(startWithName)) {
methods.add(m);
}
}
return methods;
}


public static void setParameters(Object o, Map<String, String> params) {
List<Method> methods = getSetterMethods(o.getClass());
for (String name : params.keySet()) {
String methodName = "set" + name;
for (Method m : methods) {
if (m.getName().equalsIgnoreCase(methodName)) {
try {
m.invoke(o, params.get(name));
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}


public static List<Method> getGetterMethods(Class<?> clz) {
return getMethods(clz, "get");


}


public static Map<String, Object> getParamterMap(Object o) {
Map<String, Object> params = new HashMap<>();
List<Method> methods = getGetterMethods(o.getClass());
for (Method m : methods) {
String methodName = m.getName();
String name = methodName.replaceFirst("get", "").toLowerCase();
try {
Object value = m.invoke(o);
params.put(name, value);
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return params;
}


}

最后用来实现上述要求的方法简单如斯:

public class Struts {

private final static Configuration cfg = new Configuration("struts.xml");

       public static View runAction(String actionName, Map<String,String> parameters) {

    String clzName = cfg.getClassName(actionName);
   
    if(clzName == null){
    return null;
    }
    try {
   
    Class<?> clz = Class.forName(clzName);    
Object action = clz.newInstance();
ReflectionUtil.setParameters(action, parameters);
Method m = clz.getDeclaredMethod("execute");
String resultName = (String)m.invoke(action);
Map<String,Object> params = ReflectionUtil.getParamterMap(action);
String resultView = cfg.getResultView(actionName, resultName);
View view = new View();
view.setParameters(params);
view.setJsp(resultView);
return view;
} catch (Exception e) {
e.printStackTrace();
}
    return null;
    }    

}

附:<?xml version="1.0" encoding="UTF-8"?>
<struts>
    <action name="login" class="domain.LoginAction">
        <result name="success">/jsp/homepage.jsp</result>
        <result name="fail">/jsp/showLogin.jsp</result>
    </action>
    <action name="logout" class="domain.LogoutAction">
    <result name= "success">/jsp/welcome.jsp</result>
    <result name= "error">/jsp/error.jsp</result>
    </action>
</struts>

0 0
原创粉丝点击