一直想寫Struts2的底層實現,醞釀了兩個星期,今天把它實現。
首先,我們在運用的時候都會使用action,實現跳轉,下面我們寫一個UserAction:
public class UserAction {
public String toAddUser(){
return "success";
}
public String addUser(){
return "adduser";
}
}
我們在使用Struts2的時候,一個很重要的配置文件是:struts.xml,因此我們需要讀取它,知道他裡面的內容,java解析xml我寫過了一篇文章,可以去看看。
下面我們寫一個配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<struts>
<package name="user" namespace="/user" >
<action name="userAction" class="actions.UserAction" >
<result name="success">/success.jsp</result>
<result name="adduser">/addUser.jsp</result>
</action>
</package>
</struts>
之後我們就需要去讀取這個配置文件,但是之前我們需要我們需要建立幾個實體類去存儲這些元素,由外到內排列:
1.package的實體類
import java.util.List;
public class PackageEntity {
private String name;
private String namespace;
private List<ActionEntity> actions;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNamespace() {
return namespace;
}
public void setNamespace(String namespace) {
this.namespace = namespace;
}
public List<ActionEntity> getActions() {
return actions;
}
public void setActions(List<ActionEntity> actions) {
this.actions = actions;
}
}
private List<ActionEntity> actions;是吧action實體類的內容放到package中。
2.action的實體類
import java.util.List;
public class ActionEntity {
private String name;
private String classname;
private List<ResultEntity> results;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getClassname() {
return classname;
}
public void setClassname(String classname) {
this.classname = classname;
}
public List<ResultEntity> getResults() {
return results;
}
public void setResults(List<ResultEntity> results) {
this.results = results;
}
}
private List<ResultEntity> results;是把result的實體類放到action中。
3.result的實體類
public class ResultEntity {
private String name;
private String page;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPage() {
return page;
}
public void setPage(String page) {
this.page = page;
}
}
page是指後面的jsp。
經過兩個list就把配置文件中所有的元素集中到package中,便於下面的跳轉。
下面寫一個配置的工具類:
public class ConfigUtils {
//new一個package的對象,便於調用元素
public static PackageEntity pe=new PackageEntity();
public static void config(){
SAXReader reader=new SAXReader();
try {
//讀取struts.xml
Document doc=reader.read(Thread.currentThread().getContextClassLoader().getResourceAsStream("struts.xml"));
//讀取根元素
Element root=doc.getRootElement();
//得到根元素下的節點元素
Element packageElement=root.element("package");
List<ActionEntity> actions=new ArrayList<ActionEntity>();
pe.setName(packageElement.attributeValue("name"));
pe.setNamespace(packageElement.attributeValue("namespace"));
//得到根元素下的節點元素
List<Element> listActions=packageElement.elements("action");
for(Element actionElement:listActions){
ActionEntity ae=new ActionEntity();
//得到子節點
ae.setName(actionElement.attributeValue("name"));
ae.setClassname(actionElement.attributeValue("class"));
//得到根元素下的節點元素
List<Element> resultElements=actionElement.elements("result");
List<ResultEntity> results=new ArrayList<ResultEntity>();
for(Element resultEle:resultElements){
ResultEntity re=new ResultEntity();
//得到子節點
re.setName(resultEle.attributeValue("name"));
re.setPage(resultEle.getText());
results.add(re);
}
ae.setResults(results);
actions.add(ae);
}
pe.setActions(actions);
} catch (DocumentException e) {
e.printStackTrace();
}
}
}
寫一個index.jsp,為了寫跳轉鏈接進行驗證:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>首頁</title>
</head>
<body>
<a href="<%=path%>/user/userAction!toAddUser.action">跳轉</a>
<br/>
<a href="<%=path%>/user/userAction!addUser.action">添加用戶</a>
</body>
</html>
跳轉是跳到到success.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'success.jsp' starting page</title>
</head>
<body>
This is my JSP page. <br>
成功了
</body>
</html>
添加用戶是跳到adduser.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'addUser.jsp' starting page</title>
</head>
<body>
This is my JSP page. <br>
添加用戶了
</body>
</html>
寫好了jsp之後我們就要過濾這些連接,進行跳轉,寫一個struts2的過濾器:
public class StrutsFilter implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request=(HttpServletRequest)req;
String path=request.getServletPath();
System.out.println(path);
String[] pathArr=path.split("/");
String namespace=pathArr[1];
String actionString=pathArr[2];
String actionname=actionString.split("!")[0];
String methodname=actionString.split("!")[1].split("\\.")[0];
System.out.println(actionname+":"+methodname);
PackageEntity pe=ConfigUtils.pe;
List<ActionEntity> actions=pe.getActions();
ActionEntity doAction=null;
for(ActionEntity ae:actions){
if(ae.getName().equals(actionname)){
doAction=ae;
break;
}
}
try {
Class actioncls=Class.forName(doAction.getClassname());
Object actionObj=actioncls.newInstance();
Class cls=actionObj.getClass();
Method actionMethod=cls.getDeclaredMethod(methodname);
String resultValue=(String)actionMethod.invoke(actionObj,null);
List<ResultEntity> results=doAction.getResults();
ResultEntity re=null;
for(ResultEntity result:results){
if(resultValue.equals(result.getName())){
re=result;
break;
}
}
request.getRequestDispatcher(re.getPage()).forward(request, res);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
ConfigUtils.config();
}
}
下面建立一個web的過濾器測試一下:
import java.io.IOException;
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;
public class TestFilter implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request=(HttpServletRequest)req;
HttpServletResponse response=(HttpServletResponse)res;
request.getRequestDispatcher("/success.jsp").forward(request,response);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
}
建立一個web的servlet測試一下:
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class TestServlet extends HttpServlet {
public void doGet(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{
request.getRequestDispatcher("/success.jsp").forward(request, response);
}
}
別忘了把解析xml的包導進去。
希望對你們理解框架有幫助!!!