您的位置:首页 > 编程语言 > Java开发

javaWeb-编写迷你Structs2框架并使用

2017-10-11 13:23 344 查看
miniMVC流程和项目结构:



1:创建oa.web.action包,并在其中编写两个对象的action,如:EmployeeAction和DepartmentAction:

package com._520it.oa.web.action;

public class EmployeeAction {
public void excute(){
System.out.println("员工的列表");
}
}

package com._520it.oa.web.action;

public class DepartmentAction {
public void excute(){
System.out.println("部门列表");
}
}


2.1:在源文件夹resources中编写actions.xml文件,为action节点配置name,class,method属性,代表每次请求时需要执行的对象方法:

<!-- actions.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<actions>
<action name="Employee" class="com._520it.oa.web.action.EmployeeAction" method="excute" />
<action name="Department" class="com._520it.oa.web.action.DepartmentAction" method="excute" />
</actions>


2.2:在包web.core.config中编写ActionConfig类,用来封装每一个actions.xml中action节点的信息(以后只需在actions.xml中添加action节点即可):

package com._520it.core.web.config;

//使用lombok完成get/set/toString
@Data
public class ActionConfig {
private String name;
private String className;
private String method;

public ActionConfig(String name, String className, String method) {
this.name = name;
this.className = className;
this.method = method;
}
}


2.3:在包filter中编写处理请求的过滤器:

//1.解析actions.xml文件,将actions.xml中的action节点封装成对象,在过滤器中的init中封装成ActionConfigMap
//2.在doFilter中根据请求中的信息,取出ActionConfigMap中的ActionConfig对象,利用反射创建对象并执行函数
package com._520it.core.web.filter;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import com._520it.core.web.config.ActionConfig;

/**
* @author lq
*
*/
@SuppressWarnings("all")
public class ActionFilter implements Filter {
//将action对象的配置信息封装成对象,并装在Map中,获取时方便用请求名索引
private Map<String, Object> actionConfigMap = new HashMap<>();

public void init(FilterConfig filterConfig) throws ServletException {
//1.获取文档对象
Document doc = getDocument();
//2.获取文档中所有action节点的节点集合
NodeList nodeList = doc.getElementsByTagName("action");
for (int i = 0; i < nodeList.getLength(); i++) {
//3.获取每个节点中的属性信息,并封装成配置对象
Element actionEl = (Element) nodeList.item(i);
String actionName = actionEl.getAttribute("name");
String actionClassName = actionEl.getAttribute("class");
String actionMethod = actionEl.getAttribute("method");
//4.创建配置文件对象,并放入配置文件对象映射中
ActionConfig actionConfig = new ActionConfig(actionName, actionClassName, actionMethod);
actionConfigMap.put(actionName, actionConfig);
}
}

public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
try {
//1.在过滤器中对请求和相应对象强强转成Http类型,方便处理Http请求相关操作
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
//2.得到请求中的最后一个/请求的名称
String requestUri = req.getRequestURI();
String actionName = requestUri.substring(requestUri
.lastIndexOf("/") + 1);
//3.判断配置对象映射中是否含有当前请求的信息
if (!actionConfigMap.containsKey(actionName)) {
chain.doFilter(req, resp);
}
//4.获取当前请求操作的配置对象
ActionConfig actionConfig = (ActionConfig) actionConfigMap.get(actionName);
//5.通过反射执行请求对象中的函数
Class clz = Class.forName(actionConfig.getClassName());
Object actionObj = clz.newInstance();
Method method = clz.getMethod(actionConfig.getMethod());
method.invoke(actionObj);
} catch (Exception e) {
e.printStackTrace();
}
}

public void destroy() {

}

//返回文档对象
public Document getDocument() {
DocumentBuilderFactory db = DocumentBuilderFactory.newInstance();
try {

fec9
DocumentBuilder builder = db.newDocumentBuilder();
return builder.parse(Thread.currentThread().getContextClassLoader()
.getResourceAsStream("actions.xml"));
} catch (Exception e) {
e.printStackTrace();
}
throw new RuntimeException("解析action.xml文件失败!");
}
}


3.1:如何在对象Action中得到请求中的参数信息,写一个函数ActionContext,用来封装HttpServletRequest和HttpServletResponse:

//1.含HttpServletRequest和HttpServletResponse参数的构造器,方便构造函数。
//2.既然有了这个构造器,已上两个参数就不需要setter方法了。
//3.设置一个静态私有的ActionContext对象:
静态目的就是方便该类的静态方法getContext()能调用它,
私有目的:其他类不能直接调用该变量
package com._520it.core.web;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ActionContext {
private HttpServletRequest req;
private HttpServletResponse resp;

//虽然此变量是静态的,但是是私有的,和getContext的static不重复
private static ActionContext mContext;

public ActionContext(HttpServletRequest req, HttpServletResponse resp) {
this.req = req;
this.resp = resp;
}

public static void setContext(ActionContext context){
mContext = context;
}

public static ActionContext getContext(){
return mContext;
}

//因为构造器中已经有传req和resp得ActionContext对象,此处创建get即可
public HttpServletRequest getReq() {
return req;
}
public HttpServletResponse getResp() {
return resp;
}

}


3.2:在过滤器中,将当前的环境变量存储到ActionContext对象中,方便在其他对象中操作请求的信息:

ActionContext context = new ActionContext(req, resp);
context.setContext(context);


3.3:在对象Action中调用ActionContext对象,以得到请求中的参数信息:

public class EmployeeAction {
public void excute(){
System.out.println("员工的列表");
ActionContext context = ActionContext.getContext();
String username = context.getReq().getParameter("username");
System.out.println("username=" + username);
}
}


4.但此时在对象ActionContext中有线程不安全情况:

public class EmployeeAction {
public void excute(){
System.out.println("员工的列表");
try {
Thread.sleep(8000);
} catch (InterruptedException e) {
e.printStackTrace();
}

ActionContext context = ActionContext.getContext();
String username = context.getReq().getParameter("username");
System.out.println("username=" + username);
}
}


4.1:问题:最后一次请求中的参数值会覆盖前面请求中的参数,主要原因是ActionContext中每次请求使用的是同一个该类中的ActionContext对象成员变量

4.2:解决:
为容易发生线程不安全的变量使用ThreadLocal,ThreadLocal又称为“线程局部变量”,它为每一个使用该变量的线程都提供一个变量值的副本,使每一个线程都可以独立地改变自己的副本,而不会和其他线程的副本冲突(好比每一个线程都使用的是一个新的变量),相应ActionContext的变化:


private static ThreadLocal<ActionContext> threadLocal = new ThreadLocal<>();

public static void setContext(ActionContext context){
threadLocal.set(context);
}

public static ActionContext getContext(){
return threadLocal.get();
}


5.在执行完action对象中的函数后跳转到一个页面中:

5.1:在actions.xml中的action节点展开并配置result节点,包含name,type,path,页面名字,请求类型,路径:

<actions>
<action name="Employee" class="com._520it.oa.web.action.EmployeeAction" method="excute" >
<result name="list" type="dispatcher" path="/WEB-INF/views/employee/list.html" />
<result name="edit" type="redirect" path="/WEB-INF/views/employee/edit.html" />
</action>
</actions>


5.2:在core.web.config中创建ResultConfig对象,封装result节点的属性信息:

package com._520it.core.web.config;
@Data
public class ResultConfig {
private String name;
private String type;
private String path;

public ResultConfig(String name, String type, String path) {
this.name = name;
this.type = type;
this.path = path;
}

}


5.3:在ActionConfig类中添加成员变量:

private Map<String, ResultConfig> resultConfigMap = new HashMap<>();


并提供getter和setter方法,用于封装action节点中result节点属性信息。

5.4:在过滤器中,解析actions.xml时,在每个action节点迭代时,迭代得出result属性:

//将action对象的配置信息封装成对象,并装在Map中,获取时方便用请求名索引
private Map<String, ActionConfig> actionConfigMap = new HashMap<>();
private Map<String, ResultConfig> resultConfigMap = new HashMap<>();

public void init(FilterConfig filterConfig) throws ServletException {
//1.获取文档对象
Document doc = getDocument();
//2.获取文档中所有action节点的节点集合
NodeList nodeList = doc.getElementsByTagName("action");
for (int i = 0; i < nodeList.getLength(); i++) {
//3.获取每个节点中的属性信息,并封装成配置对象
Element actionEl = (Element) nodeList.item(i);
String actionName = actionEl.getAttribute("name");
String actionClassName = actionEl.getAttribute("class");
String actionMethod = actionEl.getAttribute("method");
//4.创建配置文件对象,并放入配置文件对象映射中
ActionConfig actionConfig = new ActionConfig(actionName, actionClassName, actionMethod);
actionConfigMap.put(actionName, actionConfig);

//5.获取文档中所有result节点的节点集合
resultConfigMap = new HashMap<>();
NodeList resultNode = actionEl.getElementsByTagName("result");
for (int j = 0; j < resultNode.getLength(); j++) {
Element resultEl = (Element) resultNode.item(j);
String resultName = resultEl.getAttribute("name");
String resultType = resultEl.getAttribute("type");
String resultPath = resultEl.getAttribute("path");

ResultConfig resultConfig = new ResultConfig(resultName, resultType, resultPath);
resultConfigMap.put(resultName, resultConfig);
//6.将该action中所有result节点组成的map对象封装到actionConfig对象中
actionConfig.setResultConfigMap(resultConfigMap);
}
}
}


5.5:在doFilter中,执行完函数后,得到函数返回值(result的名称),由请求得到action的名称,得到对应ActionConfig对象,由函数返回值得到ActionConfig对象中对应的ResultConfig对象,然后根据请求类型和资源路径跳转到相应界面:

public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
try {
//1.在过滤器中对请求和相应对象强强转成Http类型,方便处理Http请求相关操作
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;

//2.将当前的环境变量存储到ActionContext对象中,方便在其他对象中操作请求的信息ActionContext context = new ActionContext(req, resp); context.setContext(context);

//3.得到请求中的最后一个/请求的名称
String requestUri = req.getRequestURI();
String actionName = requestUri.substring(requestUri
.lastIndexOf("/") + 1);
//4.判断配置对象映射中是否含有当前请求的信息
if (!actionConfigMap.containsKey(actionName)) {
chain.doFilter(req, resp);
}
//5.获取当前请求操作的配置对象
ActionConfig actionConfig = (ActionConfig) actionConfigMap.get(actionName);
//6.通过反射执行请求对象中的函数
Class clz = Class.forName(actionConfig.getClassName());
Object actionObj = clz.newInstance();
Method method = clz.getMethod(actionConfig.getMethod());
String action = (String) method.invoke(actionObj);
System.out.println("acton=" + action);

//7.通过执行函数返回的result的name,得到该action中确切的ResultConfig对象
ResultConfig resultConfig = actionConfigMap.get(actionName).getResultConfigMap().get(action);
String type = resultConfig.getType();
String path = resultConfig.getPath();

if("dispatcher".equals(type)){
req.getRequestDispatcher(path).forward(req, resp);
System.out.println(path);
}else if("redirect".equals(type)){
resp.sendRedirect(path);
System.out.println(path);
}
} catch (Exception e) {
e.printStackTrace();
}
}


6.导出miniMVC框架:



7.使用jar包

7.1:导入jar包并buildpath.

7.2:在web.xml中配置ActionFilter前端控制器:

<filter>
<filter-name>ActionFilter</filter-name>
<filter-class>com._520it.core.web.filter.ActionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ActionFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>


7.3:书写自己的Action函数,如Product:

package A.B.C;

public class Product {
public String execute(){
System.out.println("Product.execute()");
return "welcome";
}
}


7.4:在resources源文件夹中新建actions.xml文件,并配置:

<?xml version="1.0" encoding="UTF-8"?>
<actions>
<action name="Product" class="A.B.C.Product" method="execute">
<result name="welcome" type="redirect" path="/abc.html" />
</action>
</actions>


7.5:然后在webapp中随便写个html页面,如abc.html

7.6:访问格式:http://localhost:8080/miniMVC/Product

miniMVC:tomcat根/config/server.xml中context元素属性path的值

Product:应该和action中的name向对应;

Product中的execute返回值应与result元素中的name相对应
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  structs2
相关文章推荐